GtkTree section from David Huggins-Daines <bn711@freenet.carleton.ca>, add
authorBST 1998 Tony Gale <gale@gtk.org>
Mon, 27 Jul 1998 08:21:40 +0000 (08:21 +0000)
committerTony Gale <gale@src.gnome.org>
Mon, 27 Jul 1998 08:21:40 +0000 (08:21 +0000)
Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>

        * docs/gtk_tut.sgml: GtkTree section from
          David Huggins-Daines <bn711@freenet.carleton.ca>,
          add a GtkText widget example
        * examples/text/* example/tree/* : new examples for the
          GtkTree and GtkText widgets

13 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
docs/gtk_tut.sgml
docs/tutorial/gtk_tut.sgml
examples/text/Makefile [new file with mode: 0644]
examples/text/text.c [new file with mode: 0644]
examples/tree/Makefile [new file with mode: 0644]
examples/tree/tree.c [new file with mode: 0644]

index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index 1bdf8ad760468adef92f2bf5169322dd80155908..16f2ca96fd93fdf65e1cb4ccb98f39b6c53365c8 100644 (file)
@@ -1,3 +1,11 @@
+Mon Jul 27 09:18:13 BST 1998  Tony Gale  <gale@gtk.org>
+
+       * docs/gtk_tut.sgml: GtkTree section from
+         David Huggins-Daines <bn711@freenet.carleton.ca>,
+         add a GtkText widget example
+       * examples/text/* example/tree/* : new examples for the
+         GtkTree and GtkText widgets
+
 Mon Jul 27 00:46:21 CDT 1998 Shawn T. Amundson <amundson@gtk.org>
 
        * Released GTK+ 1.1.0
index fe93a7cbac2030bbbd46d8f01d7b5612c30aedd8..d519ddbfc6c546a350974722120d2367216179b6 100644 (file)
@@ -10,7 +10,7 @@
                              name="&lt;imain@gtk.org&gt;"></tt>,
 Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
                              name="&lt;gale@gtk.org&gt;"></tt>
-<date>June 24th, 1998
+<date>July 25th, 1998
 
 <!-- ***************************************************************** -->
 <sect>Introduction
@@ -70,6 +70,9 @@ You can also view other sources of GTK information on http://www.gtk.org/
 GTK uses GNU autoconf for
 configuration.  Once untar'd, type ./configure --help to see a list of options.
 
+Th GTK source distribution also contains the complete source to all of the
+examples used in this tutorial, along with Makefiles to aid compilation.
+
 To begin our introduction to GTK, we'll start with the simplest program 
 possible.  This program will
 create a 200x200 pixel window and has no way of exiting except to be
@@ -272,6 +275,9 @@ directories for the compiler to look in, and <tt>gtk-config --libs</>
 will output the list of libraries for the compiler to link with and
 the directories to find them in.
 
+Note that the type of single quote used in the compile command above
+is significant.
+
 The libraries that are usually linked in are:
 <itemize>
 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
@@ -985,6 +991,7 @@ yourself and play with it.
 <tscreen><verb>
 /* example-start packbox packbox.c */
 
+#include <stdio.h>
 #include "gtk/gtk.h"
 
 void
@@ -5705,4227 +5712,6063 @@ Please see the GtkList example on this, which covers the usage of a
 GtkListItem as well.
 
 <!-- ***************************************************************** -->
-<sect>Menu Widgets
+<sect> Tree Widget<label id="sec_Tree_Widgets">
 <!-- ***************************************************************** -->
 <p>
-There are two ways to create menus, there's the easy way, and there's the
-hard way. Both have their uses, but you can usually use the menufactory
-(the easy way). The "hard" way is to create all the menus using the calls
-directly. The easy way is to use the gtk_menu_factory calls. This is
-much simpler, but there are advantages and disadvantages to each approach.
 
-The menufactory is much easier to use, and to add new menus to, although
-writing a few wrapper functions to create menus using the manual method 
-could go a long way towards usability. With the menufactory, it is not 
-possible to add images or the character '/' to the menus.
+The purpose of tree widgets is to display hierarchically-organized
+data. The GtkTree widget itself is a vertical container for widgets
+of type GtkTreeItem. GtkTree itself is not terribly different from
+GtkList - both are derived directly from GtkContainer, and the
+GtkContainer methods work in the same way on GtkTree widgets as on
+GtkList widgets. The difference is that GtkTree widgets can be nested
+within other GtkTree widgets. We'll see how to do this shortly.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Manual Menu Creation
+The GtkTree widget has its own window, and defaults to a white
+background, as does GtkList. Also, most of the GtkTree methods work
+in the same way as the corresponding GtkList ones. However, GtkTree
+is not derived from GtkList, so you cannot use them interchangeably.
+
+<sect1> Creating a Tree
 <p>
-In the true tradition of teaching, we'll show you the hard
-way first. <tt>:)</>
+A GtkTree is created in the usual way, using:
 
-There are three widgets that go into making a menubar and submenus:
-<itemize>
-<item>a menu item, which is what the user wants to select, e.g. 'Save'
-<item>a menu, which acts as a container for the menu items, and
-<item>a menubar, which is a container for each of the individual menus,
-</itemize>
+<tscreen><verb>
+GtkWidget* gtk_tree_new( void );
+</verb></tscreen>
 
-This is slightly complicated by the fact that menu item widgets are used
-for two different things. They are both the widets that are packed into
-the menu, and the widget that is packed into the menubar, which,
-when selected, activiates the menu.
+Like the GtkList widget, a GtkTree will simply keep growing as more
+items are added to it, as well as when subtrees are expanded.
+For this reason, they are almost always packed into a
+GtkScrolledWindow. You might want to use gtk_widget_set_usize() on
+the scrolled window to ensure that it is big enough to see the tree's
+items, as the default size for GtkScrolledWindow is quite small.
 
-Let's look at the functions that are used to create menus and menubars.
-This first function is used to create a new menubar.
+Now that you have a tree, you'll probably want to add some items to
+it.  <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
+explains the gory details of GtkTreeItem. For now, it'll suffice to
+create one, using:
 
 <tscreen><verb>
-GtkWidget *gtk_menu_bar_new( void );
+GtkWidget* gtk_tree_item_new_with_label( gchar *label );
 </verb></tscreen>
 
-This rather self explanatory function creates a new menubar.  You use
-gtk_container_add to pack this into a window, or the box_pack functions to
-pack it into a box - the same as buttons.
+You can then add it to the tree using one of the following (see
+<ref id="sec_GtkTree_Functions" name="Functions and Macros">
+below for more options):
 
 <tscreen><verb>
-GtkWidget *gtk_menu_new( void );
+void gtk_tree_append( GtkTree    *tree,
+                       GtkWidget *tree_item );
+
+void gtk_tree_prepend( GtkTree   *tree,
+                       GtkWidget *tree_item );
 </verb></tscreen>
 
-This function returns a pointer to a new menu, it is never actually shown
-(with gtk_widget_show), it is just a container for the menu items.  Hopefully this will
-become more clear when you look at the example below.
+Note that you must add items to a GtkTree one at a time - there is no
+equivalent to gtk_list_*_items().
 
-The next two calls are used to create menu items that are packed into
-the menu (and menubar).
+<sect1> Adding a Subtree
+<p>
+A subtree is created like any other GtkTree widget. A subtree is added
+to another tree beneath a tree item, using:
 
 <tscreen><verb>
-GtkWidget *gtk_menu_item_new( void );
+void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
+                                GtkWidget   *subtree );
 </verb></tscreen>
 
-and
+You do not need to call gtk_widget_show() on a subtree before or after
+adding it to a GtkTreeItem. However, you <em>must</em> have added the
+GtkTreeItem in question to a parent tree before calling
+gtk_tree_item_set_subtree(). This is because, technically, the parent
+of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
+rather the GtkTree which holds that GtkTreeItem.
+
+When you add a subtree to a GtkTreeItem, a plus or minus sign appears
+beside it, which the user can click on to "expand" or "collapse" it,
+meaning, to show or hide its subtree. GtkTreeItems are collapsed by
+default. Note that when you collapse a GtkTreeItem, any selected
+items in its subtree remain selected, which may not be what the user
+expects.
+
+<sect1> Handling the Selection List
+<p>
+As with GtkList, the GtkTree type has a <tt>selection</tt> field, and
+it is possible to control the behaviour of the tree (somewhat) by
+setting the selection type using:
 
 <tscreen><verb>
-GtkWidget *gtk_menu_item_new_with_label( const char *label );
+void gtk_tree_set_selection_mode( GtkTree          *tree,
+                                  GtkSelectionMode  mode );
 </verb></tscreen>
 
-These calls are used to create the menu items that are to be displayed.
-Remember to differentiate between a "menu" as created with gtk_menu_new
-and a "menu item" as created by the gtk_menu_item_new functions. The
-menu item will be an actual button with an associated action,
-whereas a menu will be a container holding menu items.
+The semantics associated with the various selection modes are
+described in the section on the GtkList widget.  As with the GtkList
+widget, the "select_child", "unselect_child" (not really - see <ref
+id="sec_GtkTree_Signals" name="Signals"> below for an explanation),
+and "selection_changed" signals are emitted when list items are
+selected or unselected.  However, in order to take advantage of these
+signals, you need to know <em>which</em> GtkTree widget they will be
+emitted by, and where to find the list of selected items.
 
-The gtk_menu_new_with_label and gtk_menu_new functions are just as you'd expect after
-reading about the buttons. One creates a new menu item with a label
-already packed into it, and the other just creates a blank menu item.
+This is a source of potential confusion. The best way to explain this
+is that though all GtkTree widgets are created equal, some are more
+equal than others. All GtkTree widgets have their own X window, and
+can therefore receive events such as mouse clicks (if their
+GtkTreeItems or their children don't catch them first!). However, to
+make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types
+behave in a sane manner, the list of selected items is specific to the
+topmost GtkTree widget in a hierarchy, known as the "root tree".
 
-Once you've created a menu item you have to put it into a menu. This is 
-done using the function gtk_menu_append. In order to capture when the item
-is selected by the user, we need to connect to the <tt/activate/ signal in
-the usual way. So, if we wanted to create a standard <tt/File/ menu, with
-the options <tt/Open/, <tt/Save/ and <tt/Quit/ the code would look something like
+Thus, accessing the <tt>selection</tt>field directly in an arbitrary
+GtkTree widget is not a good idea unless you <em>know</em> it's the
+root tree.  Instead, use the GTK_TREE_SELECTION (Tree) macro, which
+gives the root tree's selection list as a GList pointer. Of course,
+this list can include items that are not in the subtree in question if 
+the selection type is GTK_SELECTION_MULTIPLE.
+
+Finally, the "select_child" (and "unselect_child", in theory) signals
+are emitted by all trees, but the "selection_changed" signal is only
+emitted by the root tree. Consequently, if you want to handle the
+"select_child" signal for a tree and all its subtrees, you will have
+to call gtk_signal_connect() for every subtree.
+
+<sect1> Tree Widget Internals
+<p>
+The GtkTree's struct definition looks like this:
 
 <tscreen><verb>
-file_menu = gtk_menu_new();    /* Don't need to show menus */
+struct _GtkTree
+{
+  GtkContainer container;
 
-/* Create the menu items */
-open_item = gtk_menu_item_new_with_label("Open");
-save_item = gtk_menu_item_new_with_label("Save");
-quit_item = gtk_menu_item_new_with_label("Quit");
+  GList *children;
+  
+  GtkTree* root_tree; /* owner of selection list */
+  GtkWidget* tree_owner;
+  GList *selection;
+  guint level;
+  guint indent_value;
+  guint current_indent;
+  guint selection_mode : 2;
+  guint view_mode : 1;
+  guint view_line : 1;
+};
+</verb></tscreen>
 
-/* Add them to the menu */
-gtk_menu_append( GTK_MENU(file_menu), open_item);
-gtk_menu_append( GTK_MENU(file_menu), save_item);
-gtk_menu_append( GTK_MENU(file_menu), quit_item);
+The perils associated with accessing the <tt>selection</tt> field
+directly have already been mentioned.  The other important fields of
+the struct can also be accessed with handy macros or class functions.
+GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates
+whether a tree is the root tree in a GtkTree hierarchy, while
+GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type
+GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want
+to use one of the gtk_widget_*() functions on it).
 
-/* Attach the callback functions to the activate signal */
-gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
-                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
-gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
-                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
+Instead of directly accessing the children field of a GtkTree widget,
+it's probably best to cast it using GTK_CONTAINER (Tree), and pass it
+to the gtk_container_children() function. This creates a duplicate of
+the original list, so it's advisable to free it up using g_list_free() 
+after you're done with it, or to iterate on it destructively, like
+this:
 
-/* We can attach the Quit menu item to our exit function */
-gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
-                          GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
+<tscreen><verb>
+children = gtk_container_children (GTK_CONTAINER (tree));
+while (children) {
+  do_something_nice (GTK_TREE_ITEM (children->data));
+  children = g_list_remove_link (children, children);
+}
+</verb></tscreen>
 
-/* We do need to show menu items */
-gtk_widget_show( open_item );
-gtk_widget_show( save_item );
-gtk_widget_show( quit_item );
+The <tt>tree_owner</tt> field is defined only in subtrees, where it
+points to the GtkTreeItem widget which holds the tree in question.
+The <tt>level</tt> field indicates how deeply nested a particular tree
+is; root trees have level 0, and each successive level of subtrees has
+a level one greater than the parent level.  This field is set only
+after a GtkTree widget is actually mapped (i.e. drawn on the screen).
+
+<sect2> Signals<label id="sec_GtkTree_Signals">
+<p>
+<tscreen><verb>
+void selection_changed( GtkTree *tree );
 </verb></tscreen>
 
-At this point we have our menu. Now we need to create a menubar and a menu
-item for the <tt/File/ entry, to which we add our menu. The code looks like this 
+This signal will be emitted whenever the <tt>selection</tt> field of a
+GtkTree has changed. This happens when a child of the GtkTree is
+selected or deselected.
 
 <tscreen><verb>
-menu_bar = gtk_menu_bar_new();
-gtk_container_add( GTK_CONTAINER(window), menu_bar);
-gtk_widget_show( menu_bar );
+void select_child( GtkTree   *tree,
+                   GtkWidget *child );
+</verb></tscreen>
 
-file_item = gtk_menu_item_new_with_label("File");
-gtk_widget_show(file_item);
+This signal is emitted when a child of the GtkTree is about to get
+selected. This happens on calls to gtk_tree_select_item(),
+gtk_tree_select_child(), on <em>all</em> button presses and calls to
+gtk_tree_item_toggle() and gtk_item_toggle().  It may sometimes be
+indirectly triggered on other occasions where children get added to or
+removed from the GtkTree.
+
+<tscreen><verb>
+void unselect_child (GtkTree   *tree,
+                     GtkWidget *child);
 </verb></tscreen>
 
-Now we need to associate the menu with <tt/file_item/. This is done with the
-function
+This signal is emitted when a child of the GtkTree is about to get
+deselected. As of GTK+ 1.0.4, this seems to only occur on calls to
+gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
+other occasions, but <em>not</em> when a button press deselects a
+child, nor on emission of the "toggle" signal by gtk_item_toggle().
 
-<tscreen>
-void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
-                                GtkWidget   *submenu );
-</tscreen>
+<sect2> Functions and Macros<label id="sec_GtkTree_Functions">
+<p>
+<tscreen><verb>
+guint gtk_tree_get_type( void );
+</verb></tscreen>
 
-So, our example would continue with
+Returns the `GtkTree' type identifier.
 
 <tscreen><verb>
-gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
+GtkWidget* gtk_tree_new( void );
 </verb></tscreen>
 
-All that is left to do is to add the menu to the menubar, which is accomplished
-using the function
+Create a new GtkTree object. The new widget is returned as a pointer to a
+GtkWidget object. NULL is returned on failure.
 
-<tscreen>
-void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
-</tscreen>
+<tscreen><verb>
+void gtk_tree_append( GtkTree   *tree,
+                      GtkWidget *tree_item );
+</verb></tscreen>
 
-which in our case looks like this:
+Append a tree item to a GtkTree.
 
 <tscreen><verb>
-gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
+void gtk_tree_prepend( GtkTree   *tree,
+                       GtkWidget *tree_item );
 </verb></tscreen>
 
-If we wanted the menu right justified on the menubar, such as help menus
-often are, we can use the following function (again on <tt/file_item/
-in the current example) before attaching it to the menubar.
+Prepend a tree item to a GtkTree.
 
 <tscreen><verb>
-void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
+void gtk_tree_insert( GtkTree   *tree,
+                      GtkWidget *tree_item,
+                      gint       position );
 </verb></tscreen>
 
-Here is a summary of the steps needed to create a menu bar with menus attached:
+Insert a tree item into a GtkTree at the position in the list
+specified by <tt>position.</tt>
 
-<itemize>
-<item> Create a new menu using gtk_menu_new()
-<item> Use multiple calls to gtk_menu_item_new() for each item you wish to have
-on your menu. And use gtk_menu_append() to put each of these new items on 
-to the menu.
-<item> Create a menu item using gtk_menu_item_new(). This will be the root of
-the menu, the text appearing here will be on the menubar itself.
-<item>Use gtk_menu_item_set_submenu() to attach the menu to the root menu 
-item (the one created in the above step).
-<item> Create a new menubar using gtk_menu_bar_new. This step only needs
-to be done once when creating a series of menus on one menu bar.
-<item> Use gtk_menu_bar_append to put the root menu onto the menubar.
-</itemize>
+<tscreen><verb>
+void gtk_tree_remove_items( GtkTree *tree,
+                            GList   *items );
+</verb></tscreen>
 
-Creating a popup menu is nearly the same. The difference is that the
-menu is not posted `automatically' by a menubar, but explicitly by calling
-the function gtk_menu_popup() from a button-press event, for example.
-Take these steps:
+Remove a list of items (in the form of a GList *) from a GtkTree.
+Note that removing an item from a tree dereferences (and thus usually)
+destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
+subtrees in that subtree.  If you want to remove only one item, you
+can use gtk_container_remove().
 
-<itemize>
-<item>Create an event handling function. It needs to have the prototype
-<tscreen>
-static gint handler( GtkWidget *widget,
-                     GdkEvent  *event );
-</tscreen>
-and it will use the event to find out where to pop up the menu.
-<item>In the event handler, if the event is a mouse button press, treat
-<tt>event</tt> as a button event (which it is) and use it as
-shown in the sample code to pass information to gtk_menu_popup().
-<item>Bind that event handler to a widget with
-<tscreen>
-gtk_signal_connect_object(GTK_OBJECT(widget), "event",
-                          GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
-</tscreen>
-where <tt>widget</tt> is the widget you are binding to, <tt>handler</tt>
-is the handling function, and <tt>menu</tt> is a menu created with
-gtk_menu_new().  This can be a menu which is also posted by a menu bar,
-as shown in the sample code.
-</itemize>
+<tscreen><verb>
+void gtk_tree_clear_items( GtkTree *tree,
+                           gint     start,
+                           gint     end );
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Manual Menu Example
-<p>
-That should about do it.  Let's take a look at an example to help clarify.
+Remove the items from position <tt>start</tt> to position <tt>end</tt>
+from a GtkTree.  The same warning about dereferencing applies here, as
+gtk_tree_clear_items() simply constructs a list and passes it to
+gtk_tree_remove_items().
 
 <tscreen><verb>
-/* example-start menu menu.c */
+void gtk_tree_select_item( GtkTree *tree,
+                           gint     item );
+</verb></tscreen>
 
-#include <gtk/gtk.h>
+Emits the "select_item" signal for the child at position
+<tt>item</tt>, thus selecting the child (unless you unselect it in a
+signal handler...)
 
-static gint button_press (GtkWidget *, GdkEvent *);
-static void menuitem_response (gchar *);
+<tscreen><verb>
+void gtk_tree_unselect_item( GtkTree *tree,
+                             gint     item );
+</verb></tscreen>
 
-int main (int argc, char *argv[])
-{
+Emits the "unselect_item" signal for the child at position
+<tt>item</tt>, thus unselecting the child.
 
-    GtkWidget *window;
-    GtkWidget *menu;
-    GtkWidget *menu_bar;
-    GtkWidget *root_menu;
-    GtkWidget *menu_items;
-    GtkWidget *vbox;
-    GtkWidget *button;
-    char buf[128];
-    int i;
+<tscreen><verb>
+void gtk_tree_select_child( GtkTree   *tree,
+                            GtkWidget *tree_item );
+</verb></tscreen>
 
-    gtk_init (&amp;argc, &amp;argv);
+Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
+selecting it.
 
-    /* create a new window */
-    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
-    gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
-    gtk_signal_connect(GTK_OBJECT (window), "delete_event",
-                       (GtkSignalFunc) gtk_main_quit, NULL);
+<tscreen><verb>
+void gtk_tree_unselect_child( GtkTree   *tree,
+                              GtkWidget *tree_item );
+</verb></tscreen>
 
-    /* Init the menu-widget, and remember -- never
-     * gtk_show_widget() the menu widget!! 
-     * This is the menu that holds the menu items, the one that
-     * will pop up when you click on the "Root Menu" in the app */
-    menu = gtk_menu_new();
+Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
+thus unselecting it.
 
-    /* Next we make a little loop that makes three menu-entries for "test-menu".
-     * Notice the call to gtk_menu_append.  Here we are adding a list of
-     * menu items to our menu.  Normally, we'd also catch the "clicked"
-     * signal on each of the menu items and setup a callback for it,
-     * but it's omitted here to save space. */
+<tscreen><verb>
+gint gtk_tree_child_position( GtkTree   *tree,
+                              GtkWidget *child );
+</verb></tscreen>
 
-    for(i = 0; i < 3; i++)
-        {
-            /* Copy the names to the buf. */
-            sprintf(buf, "Test-undermenu - %d", i);
+Returns the position in the tree of <tt>child</tt>, unless
+<tt>child</tt> is not in the tree, in which case it returns -1.
 
-            /* Create a new menu-item with a name... */
-            menu_items = gtk_menu_item_new_with_label(buf);
+<tscreen><verb>
+void gtk_tree_set_selection_mode( GtkTree          *tree,
+                                  GtkSelectionMode  mode );
+</verb></tscreen>
 
-            /* ...and add it to the menu. */
-            gtk_menu_append(GTK_MENU (menu), menu_items);
+Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the
+default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or
+GTK_SELECTION_EXTENDED. This is only defined for root trees, which
+makes sense, since the root tree "owns" the selection. Setting it for
+subtrees has no effect at all; the value is simply ignored.
 
-           /* Do something interesting when the menuitem is selected */
-           gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
-               GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
+<tscreen><verb>
+void gtk_tree_set_view_mode( GtkTree         *tree,
+                             GtkTreeViewMode  mode ); 
+</verb></tscreen>
 
-            /* Show the widget */
-            gtk_widget_show(menu_items);
-        }
+Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the
+default) or GTK_TREE_VIEW_ITEM.  The view mode propagates from a tree
+to its subtrees, and can't be set exclusively to a subtree (this is
+not exactly true - see the example code comments).
 
-    /* This is the root menu, and will be the label
-     * displayed on the menu bar.  There won't be a signal handler attached,
-     * as it only pops up the rest of the menu when pressed. */
-    root_menu = gtk_menu_item_new_with_label("Root Menu");
+The term "view mode" is rather ambiguous - basically, it controls the
+way the hilight is drawn when one of a tree's children is selected.
+If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is
+hilighted, while for GTK_TREE_VIEW_ITEM, only the child widget
+(i.e. usually the label) is hilighted.
 
-    gtk_widget_show(root_menu);
+<tscreen><verb>
+void gtk_tree_set_view_lines( GtkTree *tree,
+                              guint    flag );
+</verb></tscreen>
 
-    /* Now we specify that we want our newly created "menu" to be the menu
-     * for the "root menu" */
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
+Controls whether connecting lines between tree items are drawn.
+<tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
+which case they aren't.
 
-    /* A vbox to put a menu and a button in: */
-    vbox = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(window), vbox);
-    gtk_widget_show(vbox);
+<tscreen><verb>
+GtkTree *GTK_TREE (gpointer obj);
+</verb></tscreen>
 
-    /* Create a menu-bar to hold the menus and add it to our main window */
-    menu_bar = gtk_menu_bar_new();
-    gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
-    gtk_widget_show(menu_bar);
+Cast a generic pointer to `GtkTree *'.
 
-    /* Create a button to which to attach menu as a popup */
-    button = gtk_button_new_with_label("press me");
-    gtk_signal_connect_object(GTK_OBJECT(button), "event",
-       GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
-    gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
-    gtk_widget_show(button);
+<tscreen><verb>
+GtkTreeClass *GTK_TREE_CLASS (gpointer class);
+</verb></tscreen>
 
-    /* And finally we append the menu-item to the menu-bar -- this is the
-     * "root" menu-item I have been raving about =) */
-    gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
+Cast a generic pointer to `GtkTreeClass*'.
 
-    /* always display the window as the last step so it all splashes on
-     * the screen at once. */
-    gtk_widget_show(window);
+<tscreen><verb>
+gint GTK_IS_TREE (gpointer obj);
+</verb></tscreen>
 
-    gtk_main ();
+Determine if a generic pointer refers to a `GtkTree' object.
 
-    return 0;
-}
+<tscreen><verb>
+gint GTK_IS_ROOT_TREE (gpointer obj)
+</verb></tscreen>
 
-/* Respond to a button-press by posting a menu passed in as widget.
- *
- * Note that the "widget" argument is the menu being posted, NOT
- * the button that was pressed.
- */
+Determine if a generic pointer refers to a `GtkTree' object
+<em>and</em> is a root tree. Though this will accept any pointer, the
+results of passing it a pointer that does not refer to a GtkTree are
+undefined and possibly harmful.
 
-static gint button_press (GtkWidget *widget, GdkEvent *event)
-{
+<tscreen><verb>
+GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
+</verb></tscreen>
 
-    if (event->type == GDK_BUTTON_PRESS) {
-        GdkEventButton *bevent = (GdkEventButton *) event; 
-        gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
-                        bevent->button, bevent->time);
-        /* Tell calling code that we have handled this event; the buck
-         * stops here. */
-        return TRUE;
-    }
+Return the root tree of a pointer to a `GtkTree' object. The above
+warning applies.
 
-    /* Tell calling code that we have not handled this event; pass it on. */
-    return FALSE;
-}
+<tscreen><verb>
+GList *GTK_TREE_SELECTION( gpointer obj)
+</verb></tscreen>
 
+Return the selection list of the root tree of a `GtkTree' object. The 
+above warning applies here, too.
 
-/* Print a string when a menu item is selected */
+<sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
+<p>
+The GtkTreeItem widget, like GtkListItem, is derived from GtkItem,
+which in turn is derived from GtkBin.  Therefore, the item itself is a
+generic container holding exactly one child widget, which can be of
+any type.  The GtkTreeItem widget has a number of extra fields, but
+the only one we need be concerned with is the <tt>subtree</tt> field.
 
-static void menuitem_response (gchar *string)
+The definition for the GtkTreeItem struct looks like this:
+
+<tscreen><verb>
+struct _GtkTreeItem
 {
-    printf("%s\n", string);
+  GtkItem item;
+
+  GtkWidget *subtree;
+  GtkWidget *pixmaps_box;
+  GtkWidget *plus_pix_widget, *minus_pix_widget;
+
+  GList *pixmaps;              /* pixmap node for this items color depth */
+
+  guint expanded : 1;
+};
+</verb></tscreen>
+
+The <tt>pixmaps_box</tt> field is a GtkEventBox which catches clicks
+on the plus/minus symbol which controls expansion and collapsing.  The
+<tt>pixmaps</tt> field points to an internal data structure.  Since
+you can always obtain the subtree of a GtkTreeItem in a (relatively)
+type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's
+probably advisable never to touch the insides of a GtkTreeItem unless
+you <em>really</em> know what you're doing.
+
+Since it is directly derived from a GtkItem it can be treated as such
+by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a
+label, so the convenience function gtk_list_item_new_with_label() is
+provided. The same effect can be achieved using code like the
+following, which is actually copied verbatim from
+gtk_tree_item_new_with_label():
+
+<tscreen><verb>
+tree_item = gtk_tree_item_new ();
+label_widget = gtk_label_new (label);
+gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
+
+gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
+gtk_widget_show (label_widget);
+</verb></tscreen>
+
+As one is not forced to add a GtkLabel to a GtkTreeItem, you could
+also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your
+app will likely be quite unpopular in this case) to the GtkTreeItem.
+
+If you remove all the items from a subtree, it will be destroyed and
+unparented, unless you reference it beforehand, and the GtkTreeItem
+which owns it will be collapsed.  So, if you want it to stick around,
+do something like the following:
+
+<tscreen><verb>
+gtk_widget_ref (tree);
+owner = GTK_TREE(tree)->tree_owner;
+gtk_container_remove (GTK_CONTAINER(tree), item);
+if (tree->parent == NULL){
+  gtk_tree_item_expand (GTK_TREE_ITEM(owner));
+  gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
 }
-/* example-end */
+else
+  gtk_widget_unref (tree);
 </verb></tscreen>
 
-You may also set a menu item to be insensitive and, using an accelerator
-table, bind keys to menu functions.
+Finally, drag-n-drop <em>does</em> work with GtkTreeItems.  You just
+have to make sure that the GtkTreeItem you want to make into a drag
+item or a drop site has not only been added to a GtkTree, but that
+each successive parent widget has a parent itself, all the way back to
+a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
+or gtk_widget_dnd_drop_set().  Otherwise, strange things will happen.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Using GtkMenuFactory
+<sect2> Signals
 <p>
-Now that we've shown you the hard way, here's how you do it using the
-gtk_menu_factory calls.
+GtkTreeItem inherits the "select", "deselect", and "toggle" signals
+from GtkItem.  In addition, it adds two signals of its own, "expand"
+and "collapse".
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Menu Factory Example
+<tscreen><verb>
+void select( GtkItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when an item is about to be selected, either
+after it has been clicked on by the user, or when the program calls
+gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
+
+<tscreen><verb>
+void deselect( GtkItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when an item is about to be unselected, either
+after it has been clicked on by the user, or when the program calls
+gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
+GtkTreeItems, it is also emitted by gtk_tree_unselect_child(), and
+sometimes gtk_tree_select_child().
+
+<tscreen><verb>
+void toggle( GtkItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when the program calls gtk_item_toggle().  The
+effect it has when emitted on a GtkTreeItem is to call
+gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
+item's parent tree, if the item has a parent tree.  If it doesn't,
+then the highlight is reversed on the item.
+
+<tscreen><verb>
+void expand( GtkTreeItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when the tree item's subtree is about to be
+expanded, that is, when the user clicks on the plus sign next to the
+item, or when the program calls gtk_tree_item_expand().
+
+<tscreen><verb>
+void collapse( GtkTreeItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when the tree item's subtree is about to be
+collapsed, that is, when the user clicks on the minus sign next to the
+item, or when the program calls gtk_tree_item_collapse().
+
+<sect2> Functions and Macros
 <p>
-Here is an example using the GTK menu factory.  This is the first file,
-menufactory.h.  We keep a separate menufactory.c and mfmain.c because
-of the global variables used in the menufactory.c file.  
+<tscreen><verb>
+guint gtk_tree_item_get_type( void );
+</verb></tscreen>
+
+Returns the `GtkTreeItem' type identifier.
 
 <tscreen><verb>
-/* example-start menu menufactory.h */
+GtkWidget* gtk_tree_item_new( void );
+</verb></tscreen>
 
-#ifndef __MENUFACTORY_H__
-#define __MENUFACTORY_H__
+Create a new GtkTreeItem object. The new widget is returned as a pointer
+to a GtkWidget object. NULL is returned on failure.
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+<tscreen><verb>
+GtkWidget* gtk_tree_item_new_with_label (gchar       *label);
+</verb></tscreen>
 
-void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
-void menus_create(GtkMenuEntry *entries, int nmenu_entries);
+Create a new GtkTreeItem object, having a single GtkLabel as
+the sole child. The new widget is returned as a pointer to a
+GtkWidget object. NULL is returned on failure.
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+<tscreen><verb>
+void gtk_tree_item_select( GtkTreeItem *tree_item );
+</verb></tscreen>
 
-#endif /* __MENUFACTORY_H__ */
-/* example-end */
+This function is basicaly a wrapper around a call to
+gtk_item_select (GTK_ITEM (tree_item)) which will emit the
+select signal.
+
+<tscreen><verb>
+void gtk_tree_item_deselect( GtkTreeItem *tree_item );
 </verb></tscreen>
 
-And here is the menufactory.c file.
+This function is basicaly a wrapper around a call to
+gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the
+deselect signal.
 
 <tscreen><verb>
-/* example-start menu menufactory.c */
+void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
+                                GtkWidget   *subtree );
+</verb></tscreen>
 
-#include <gtk/gtk.h>
-#include <strings.h>
+This function adds subtree to tree_item, showing it if tree_item is
+expanded, or hiding it if tree_item is collapsed. Again, remember
+that the tree_item must have already been added to a tree for this to
+work.
 
-#include "mfmain.h"
+<tscreen><verb>
+void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
+</verb></tscreen>
 
+This removes all of tree_item's subtree's children (thus unreferencing
+and destroying it, any of its children's subtrees, and so on...), then
+removes the subtree itself, and hides the plus/minus sign.
 
-static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
-static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
-void menus_init(void);
-void menus_create(GtkMenuEntry * entries, int nmenu_entries);
+<tscreen><verb>
+void gtk_tree_item_expand( GtkTreeItem *tree_item );
+</verb></tscreen>
 
+This emits the "expand" signal on tree_item, which expands it.
 
-/* this is the GtkMenuEntry structure used to create new menus.  The
- * first member is the menu definition string.  The second, the
- * default accelerator key used to access this menu function with
- * the keyboard.  The third is the callback function to call when
- * this menu item is selected (by the accelerator key, or with the
- * mouse.) The last member is the data to pass to your callback function.
- */
+<tscreen><verb>
+void gtk_tree_item_collapse( GtkTreeItem *tree_item );
+</verb></tscreen>
 
-static GtkMenuEntry menu_items[] =
-{
-       {"<Main>/File/New", "<control>N", NULL, NULL},
-       {"<Main>/File/Open", "<control>O", NULL, NULL},
-       {"<Main>/File/Save", "<control>S", NULL, NULL},
-       {"<Main>/File/Save as", NULL, NULL, NULL},
-       {"<Main>/File/<separator>", NULL, NULL, NULL},
-       {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
-       {"<Main>/Options/Test", NULL, NULL, NULL}
-};
+This emits the "collapse" signal on tree_item, which collapses it.
 
-/* calculate the number of menu_item's */
-static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
+<tscreen><verb>
+GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
+</verb></tscreen>
 
-static int initialize = TRUE;
-static GtkMenuFactory *factory = NULL;
-static GtkMenuFactory *subfactory[1];
-static GHashTable *entry_ht = NULL;
+Cast a generic pointer to `GtkTreeItem*'.
 
-void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
+<tscreen><verb>
+GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
+</verb></tscreen>
+
+Cast a generic pointer to `GtkTreeItemClass'.
+
+<tscreen><verb>
+gint GTK_IS_TREE_ITEM (gpointer obj)
+</verb></tscreen>
+
+Determine if a generic pointer refers to a `GtkTreeItem' object.
+<tscreen><verb>
+GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
+</verb></tscreen>
+
+Return's a tree item's subtree (obj should point to a `GtkTreeItem'
+object).
+
+<sect1> Tree Example
+<p>
+This is somewhat like the tree example in testgtk.c, but a lot less
+complete (although much better commented).  It puts up a window with a
+tree, and connects all the signals for the relevant objects, so you
+can see when they are emitted.
+
+<tscreen><verb>
+/* example-start tree tree.c */
+
+#include <gtk/gtk.h>
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal (GtkWidget *item, gchar *signame)
 {
-    if (initialize)
-           menus_init();
-    
-    if (menubar)
-           *menubar = subfactory[0]->widget;
-    if (table)
-           *table = subfactory[0]->table;
+  gchar *name;
+  GtkLabel *label;
+
+  /* It's a GtkBin, so it has one child, which we know to be a
+     label, so get that */
+  label = GTK_LABEL (GTK_BIN (item)->child);
+  /* Get the text of the label */
+  gtk_label_get (label, &amp;name);
+  /* Get the level of the tree which the item is in */
+  g_print ("%s called for item %s->%p, level %d\n", signame, name,
+          item, GTK_TREE (item->parent)->level);
 }
 
-void menus_init(void)
+/* Note that this is never called */
+static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
+                              GtkWidget *subtree)
 {
-    if (initialize) {
-       initialize = FALSE;
-       
-       factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
-       subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
-       
-       gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
-       menus_create(menu_items, nmenu_items);
-    }
+  g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
 }
 
-void menus_create(GtkMenuEntry * entries, int nmenu_entries)
+/* Note that this is called every time the user clicks on an item,
+   whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+                            GtkWidget *subtree)
 {
-    char *accelerator;
-    int i;
-    
-    if (initialize)
-           menus_init();
-    
-    if (entry_ht)
-           for (i = 0; i < nmenu_entries; i++) {
-               accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
-               if (accelerator) {
-                   if (accelerator[0] == '\0')
-                           entries[i].accelerator = NULL;
-                   else
-                           entries[i].accelerator = accelerator;
-               }
-           }
-    gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
-    
-    for (i = 0; i < nmenu_entries; i++)
-           if (entries[i].widget) {
-               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
-                                  (GtkSignalFunc) menus_install_accel,
-                                  entries[i].path);
-               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
-                                  (GtkSignalFunc) menus_remove_accel,
-                                  entries[i].path);
-           }
+  g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
 }
 
-static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
+static void cb_selection_changed (GtkWidget *tree)
 {
-    char accel[64];
-    char *t1, t2[2];
-    
-    accel[0] = '\0';
-    if (modifiers & GDK_CONTROL_MASK)
-           strcat(accel, "<control>");
-    if (modifiers & GDK_SHIFT_MASK)
-           strcat(accel, "<shift>");
-    if (modifiers & GDK_MOD1_MASK)
-           strcat(accel, "<alt>");
-    
-    t2[0] = key;
-    t2[1] = '\0';
-    strcat(accel, t2);
-    
-    if (entry_ht) {
-       t1 = g_hash_table_lookup(entry_ht, path);
-       g_free(t1);
-    } else
-           entry_ht = g_hash_table_new(g_str_hash, g_str_equal);
-    
-    g_hash_table_insert(entry_ht, path, g_strdup(accel));
-    
-    return TRUE;
+  GList *i;
+  
+  g_print ("selection_change called for tree %p\n", tree);
+  g_print ("selected objects are:\n");
+
+  i = GTK_TREE_SELECTION(tree);
+  while (i){
+    gchar *name;
+    GtkLabel *label;
+    GtkWidget *item;
+
+    /* Get a GtkWidget pointer from the list node */
+    item = GTK_WIDGET (i->data);
+    label = GTK_LABEL (GTK_BIN (item)->child);
+    gtk_label_get (label, &amp;name);
+    g_print ("\t%s on level %d\n", name, GTK_TREE
+            (item->parent)->level);
+    i = i->next;
+  }
 }
 
-static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
+int main (int argc, char *argv[])
 {
-    char *t;
-    
-    if (entry_ht) {
-       t = g_hash_table_lookup(entry_ht, path);
-       g_free(t);
-       
-       g_hash_table_insert(entry_ht, path, g_strdup(""));
+  GtkWidget *window, *scrolled_win, *tree;
+  static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
+                              "Maurice"};
+  gint i;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  /* a generic toplevel window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+  gtk_container_border_width (GTK_CONTAINER(window), 5);
+
+  /* A generic scrolled window */
+  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_widget_set_usize (scrolled_win, 150, 200);
+  gtk_container_add (GTK_CONTAINER(window), scrolled_win);
+  gtk_widget_show (scrolled_win);
+  
+  /* Create the root tree */
+  tree = gtk_tree_new();
+  g_print ("root tree is %p\n", tree);
+  /* connect all GtkTree:: signals */
+  gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+                     GTK_SIGNAL_FUNC(cb_select_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+                     GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+                     GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+  /* Add it to the scrolled window */
+  gtk_container_add (GTK_CONTAINER(scrolled_win), tree);
+  /* Set the selection mode */
+  gtk_tree_set_selection_mode (GTK_TREE(tree),
+                              GTK_SELECTION_MULTIPLE);
+  /* Show it */
+  gtk_widget_show (tree);
+
+  for (i = 0; i < 5; i++){
+    GtkWidget *subtree, *item;
+    gint j;
+
+    /* Create a tree item */
+    item = gtk_tree_item_new_with_label (itemnames[i]);
+    /* Connect all GtkItem:: and GtkTreeItem:: signals */
+    gtk_signal_connect (GTK_OBJECT(item), "select",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+    gtk_signal_connect (GTK_OBJECT(item), "deselect",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+    gtk_signal_connect (GTK_OBJECT(item), "toggle",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+    gtk_signal_connect (GTK_OBJECT(item), "expand",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+    gtk_signal_connect (GTK_OBJECT(item), "collapse",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+    /* Add it to the parent tree */
+    gtk_tree_append (GTK_TREE(tree), item);
+    /* Show it - this can be done at any time */
+    gtk_widget_show (item);
+    /* Create this item's subtree */
+    subtree = gtk_tree_new();
+    g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
+            subtree);
+
+    /* This is still necesary if you want these signals to be called
+       for the subtree's children.  Note that selection_change will be 
+       signalled for the root tree regardless. */
+    gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+                       GTK_SIGNAL_FUNC(cb_select_child), subtree);
+    gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+                       GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
+    /* This has absolutely no effect, because it is completely ignored 
+       in subtrees */
+    gtk_tree_set_selection_mode (GTK_TREE(subtree),
+                                GTK_SELECTION_SINGLE);
+    /* Neither does this, but for a rather different reason - the
+       view_mode and view_line values of a tree are propagated to
+       subtrees when they are mapped.  So, setting it later on would
+       actually have a (somewhat unpredictable) effect */
+    gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
+    /* Set this item's subtree - note that you cannot do this until
+       AFTER the item has been added to its parent tree! */
+    gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
+
+    for (j = 0; j < 5; j++){
+      GtkWidget *subitem;
+
+      /* Create a subtree item, in much the same way */
+      subitem = gtk_tree_item_new_with_label (itemnames[j]);
+      /* Connect all GtkItem:: and GtkTreeItem:: signals */
+      gtk_signal_connect (GTK_OBJECT(subitem), "select",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+      gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+      gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+      gtk_signal_connect (GTK_OBJECT(subitem), "expand",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+      gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+      g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
+      /* Add it to its parent tree */
+      gtk_tree_append (GTK_TREE(subtree), subitem);
+      /* Show it */
+      gtk_widget_show (subitem);
     }
-}
+  }
 
-void menus_set_sensitive(char *path, int sensitive)
-{
-    GtkMenuPath *menu_path;
-    
-    if (initialize)
-           menus_init();
-    
-    menu_path = gtk_menu_factory_find(factory, path);
-    if (menu_path)
-           gtk_widget_set_sensitive(menu_path->widget, sensitive);
-    else
-           g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path);
+  /* Show the window and loop endlessly */
+  gtk_widget_show (window);
+  gtk_main();
+  return 0;
 }
 /* example-end */
 </verb></tscreen>
 
-And here's the mfmain.h
-
-<tscreen><verb>
-/* example-start menu mfmain.h */
+<!-- ***************************************************************** -->
+<sect>Menu Widget
+<!-- ***************************************************************** -->
+<p>
+There are two ways to create menus, there's the easy way, and there's the
+hard way. Both have their uses, but you can usually use the menufactory
+(the easy way). The "hard" way is to create all the menus using the calls
+directly. The easy way is to use the gtk_menu_factory calls. This is
+much simpler, but there are advantages and disadvantages to each approach.
 
-#ifndef __MFMAIN_H__
-#define __MFMAIN_H__
+The menufactory is much easier to use, and to add new menus to, although
+writing a few wrapper functions to create menus using the manual method 
+could go a long way towards usability. With the menufactory, it is not 
+possible to add images or the character '/' to the menus.
 
+<!-- ----------------------------------------------------------------- -->
+<sect1>Manual Menu Creation
+<p>
+In the true tradition of teaching, we'll show you the hard
+way first. <tt>:)</>
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+There are three widgets that go into making a menubar and submenus:
+<itemize>
+<item>a menu item, which is what the user wants to select, e.g. 'Save'
+<item>a menu, which acts as a container for the menu items, and
+<item>a menubar, which is a container for each of the individual menus,
+</itemize>
 
-void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
+This is slightly complicated by the fact that menu item widgets are used
+for two different things. They are both the widets that are packed into
+the menu, and the widget that is packed into the menubar, which,
+when selected, activiates the menu.
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+Let's look at the functions that are used to create menus and menubars.
+This first function is used to create a new menubar.
 
-#endif /* __MFMAIN_H__ */
-/* example-end */
+<tscreen><verb>
+GtkWidget *gtk_menu_bar_new( void );
 </verb></tscreen>
 
-And mfmain.c
+This rather self explanatory function creates a new menubar.  You use
+gtk_container_add to pack this into a window, or the box_pack functions to
+pack it into a box - the same as buttons.
 
 <tscreen><verb>
-/* example-start menu mfmain.c */
-
-#include <gtk/gtk.h>
-
-#include "mfmain.h"
-#include "menufactory.h"
+GtkWidget *gtk_menu_new( void );
+</verb></tscreen>
 
+This function returns a pointer to a new menu, it is never actually shown
+(with gtk_widget_show), it is just a container for the menu items.  Hopefully this will
+become more clear when you look at the example below.
 
-int main(int argc, char *argv[])
-{
-    GtkWidget *window;
-    GtkWidget *main_vbox;
-    GtkWidget *menubar;
-    
-    GtkAcceleratorTable *accel;
-    
-    gtk_init(&amp;argc, &amp;argv);
-    
-    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_signal_connect(GTK_OBJECT(window), "destroy", 
-                      GTK_SIGNAL_FUNC(file_quit_cmd_callback), 
-                      "WM destroy");
-    gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
-    gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
-    
-    main_vbox = gtk_vbox_new(FALSE, 1);
-    gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
-    gtk_container_add(GTK_CONTAINER(window), main_vbox);
-    gtk_widget_show(main_vbox);
-    
-    get_main_menu(&amp;menubar, &amp;accel);
-    gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
-    gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
-    gtk_widget_show(menubar);
-    
-    gtk_widget_show(window);
-    gtk_main();
-    
-    return(0);
-}
+The next two calls are used to create menu items that are packed into
+the menu (and menubar).
 
-/* This is just to demonstrate how callbacks work when using the
- * menufactory.  Often, people put all the callbacks from the menus
- * in a separate file, and then have them call the appropriate functions
- * from there.  Keeps it more organized. */
-void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
-{
-    g_print ("%s\n", (char *) data);
-    gtk_exit(0);
-}
-/* example-end */
+<tscreen><verb>
+GtkWidget *gtk_menu_item_new( void );
 </verb></tscreen>
 
-And a makefile so it'll be easier to compile it.
+and
 
 <tscreen><verb>
-# Makefile.mf
+GtkWidget *gtk_menu_item_new_with_label( const char *label );
+</verb></tscreen>
 
-CC      = gcc
-PROF    = -g
-C_FLAGS =  -Wall $(PROF) -L/usr/local/include -DDEBUG
-L_FLAGS =  $(PROF) -L/usr/X11R6/lib -L/usr/local/lib 
-L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
-PROGNAME = menufactory
+These calls are used to create the menu items that are to be displayed.
+Remember to differentiate between a "menu" as created with gtk_menu_new
+and a "menu item" as created by the gtk_menu_item_new functions. The
+menu item will be an actual button with an associated action,
+whereas a menu will be a container holding menu items.
 
-O_FILES = menufactory.o mfmain.o
+The gtk_menu_new_with_label and gtk_menu_new functions are just as you'd expect after
+reading about the buttons. One creates a new menu item with a label
+already packed into it, and the other just creates a blank menu item.
 
-$(PROGNAME): $(O_FILES)
-       rm -f $(PROGNAME)
-       $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
+Once you've created a menu item you have to put it into a menu. This is 
+done using the function gtk_menu_append. In order to capture when the item
+is selected by the user, we need to connect to the <tt/activate/ signal in
+the usual way. So, if we wanted to create a standard <tt/File/ menu, with
+the options <tt/Open/, <tt/Save/ and <tt/Quit/ the code would look something like
 
-.c.o: 
-       $(CC) -c $(C_FLAGS) $<
+<tscreen><verb>
+file_menu = gtk_menu_new();    /* Don't need to show menus */
 
-clean: 
-       rm -f core *.o $(PROGNAME) nohup.out
-distclean: clean 
-       rm -f *~
-</verb></tscreen>
+/* Create the menu items */
+open_item = gtk_menu_item_new_with_label("Open");
+save_item = gtk_menu_item_new_with_label("Save");
+quit_item = gtk_menu_item_new_with_label("Quit");
 
-For now, there's only this example.  An explanation and lots 'o' comments
-will follow later.
+/* Add them to the menu */
+gtk_menu_append( GTK_MENU(file_menu), open_item);
+gtk_menu_append( GTK_MENU(file_menu), save_item);
+gtk_menu_append( GTK_MENU(file_menu), quit_item);
 
-<!-- ***************************************************************** -->
-<sect> Text Widget
-<!-- ***************************************************************** -->
-<p>
-The Text widget allows multiple lines of text to be displayed and edited.
-It supports both multi-colored and multi-font text, allowing them to be
-mixed in any way we wish. It also has a wide set of key based text editing
-commands, which are compatible with Emacs.
+/* Attach the callback functions to the activate signal */
+gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
+                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
+gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
+                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
 
-The text widget supports full cut-and-paste facilities, including the use
-of double- and triple-click to select a word and a whole line, respectively.
+/* We can attach the Quit menu item to our exit function */
+gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
+                          GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Creating and Configuring a Text box
-<p>
-There is only one function for creating a new Text widget.
-<tscreen><verb>
-GtkWidget *gtk_text_new( GtkAdjustment *hadj,
-                         GtkAdjustment *vadj );
+/* We do need to show menu items */
+gtk_widget_show( open_item );
+gtk_widget_show( save_item );
+gtk_widget_show( quit_item );
 </verb></tscreen>
 
-The arguments allow us to give the Text widget pointers to Adjustments
-that can be used to track the viewing position of the widget. Passing NULL
-values to either or both of these arguments will cause the gtk_text_new
-function to create it's own.
+At this point we have our menu. Now we need to create a menubar and a menu
+item for the <tt/File/ entry, to which we add our menu. The code looks like this 
 
 <tscreen><verb>
-void gtk_text_set_adjustments( GtkText       *text,
-                               GtkAdjustment *hadj,
-                               GtkAdjustment *vadj );
+menu_bar = gtk_menu_bar_new();
+gtk_container_add( GTK_CONTAINER(window), menu_bar);
+gtk_widget_show( menu_bar );
+
+file_item = gtk_menu_item_new_with_label("File");
+gtk_widget_show(file_item);
 </verb></tscreen>
 
-The above function allows the horizontal and vertical adjustments of a
-Text widget to be changed at any time.
+Now we need to associate the menu with <tt/file_item/. This is done with the
+function
 
-The text widget will not automatically create it's own scrollbars when
-the amount of text to be displayed is too long for the display window. We
-therefore have to create and add them to the display layout ourselves.
+<tscreen>
+void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
+                                GtkWidget   *submenu );
+</tscreen>
+
+So, our example would continue with
 
 <tscreen><verb>
-  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
-  gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
-  gtk_widget_show (vscrollbar);
+gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
 </verb></tscreen>
 
-The above code snippet creates a new vertical scrollbar, and attaches
-it to the vertical adjustment of the text widget, <tt/text/. It then packs
-it into a box in the normal way.
+All that is left to do is to add the menu to the menubar, which is accomplished
+using the function
 
-Note, currently the GtkText widget does not support horizontal scrollbars.
+<tscreen>
+void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
+</tscreen>
 
-There are two main ways in which a Text widget can be used: to allow the
-user to edit a body of text, or to allow us to display multiple lines of
-text to the user. In order for us to switch between these modes of
-operation, the text widget has the following function:
+which in our case looks like this:
 
 <tscreen><verb>
-void gtk_text_set_editable( GtkText *text,
-                            gint     editable );
+gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
 </verb></tscreen>
 
-The <tt/editable/ argument is a TRUE or FALSE value that specifies whether
-the user is permitted to edit the contents of the Text widget. When the
-text widget is editable, it will display a cursor at the current insertion
-point.
-
-You are not, however, restricted to just using the text widget in these
-two modes. You can toggle the editable state of the text widget at any
-time, and can insert text at any time.
-
-The text widget wraps lines of text that are too long to
-fit onto a single line of the display window. It's default behaviour is
-to break words across line breaks. This can be changed using the next
-function:
+If we wanted the menu right justified on the menubar, such as help menus
+often are, we can use the following function (again on <tt/file_item/
+in the current example) before attaching it to the menubar.
 
 <tscreen><verb>
-void gtk_text_set_word_wrap( GtkText *text,
-                             gint     word_wrap );
+void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
 </verb></tscreen>
 
-Using this function allows us to specify that the text widget should
-wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
-TRUE or FALSE value.
+Here is a summary of the steps needed to create a menu bar with menus attached:
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Text Manipulation
-<P>
-The current insertion point of a Text widget can be set using
-<tscreen><verb>
-void gtk_text_set_point( GtkText *text,
-                         guint    index );
-</verb></tscreen>
+<itemize>
+<item> Create a new menu using gtk_menu_new()
+<item> Use multiple calls to gtk_menu_item_new() for each item you wish to have
+on your menu. And use gtk_menu_append() to put each of these new items on 
+to the menu.
+<item> Create a menu item using gtk_menu_item_new(). This will be the root of
+the menu, the text appearing here will be on the menubar itself.
+<item>Use gtk_menu_item_set_submenu() to attach the menu to the root menu 
+item (the one created in the above step).
+<item> Create a new menubar using gtk_menu_bar_new. This step only needs
+to be done once when creating a series of menus on one menu bar.
+<item> Use gtk_menu_bar_append to put the root menu onto the menubar.
+</itemize>
 
-where <tt/index/ is the position to set the insertion point.
+Creating a popup menu is nearly the same. The difference is that the
+menu is not posted `automatically' by a menubar, but explicitly by calling
+the function gtk_menu_popup() from a button-press event, for example.
+Take these steps:
 
-Analogous to this is the function for getting the current insertion point:
+<itemize>
+<item>Create an event handling function. It needs to have the prototype
+<tscreen>
+static gint handler( GtkWidget *widget,
+                     GdkEvent  *event );
+</tscreen>
+and it will use the event to find out where to pop up the menu.
+<item>In the event handler, if the event is a mouse button press, treat
+<tt>event</tt> as a button event (which it is) and use it as
+shown in the sample code to pass information to gtk_menu_popup().
+<item>Bind that event handler to a widget with
+<tscreen>
+gtk_signal_connect_object(GTK_OBJECT(widget), "event",
+                          GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
+</tscreen>
+where <tt>widget</tt> is the widget you are binding to, <tt>handler</tt>
+is the handling function, and <tt>menu</tt> is a menu created with
+gtk_menu_new().  This can be a menu which is also posted by a menu bar,
+as shown in the sample code.
+</itemize>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Manual Menu Example
+<p>
+That should about do it.  Let's take a look at an example to help clarify.
 
 <tscreen><verb>
-guint gtk_text_get_point( GtkText *text );
-</verb></tscreen>
+/* example-start menu menu.c */
 
-A function that is useful in combination with the above two functions is
+#include <gtk/gtk.h>
 
-<tscreen><verb>
-guint gtk_text_get_length( GtkText *text );
-</verb></tscreen>
+static gint button_press (GtkWidget *, GdkEvent *);
+static void menuitem_response (gchar *);
 
-which returns the current length of the Text widget. The length is the
-number of characters that are within the text block of the widget,
-including characters such as carriage-return, which marks the end of lines.
+int main (int argc, char *argv[])
+{
 
-In order to insert text at the current insertion point of a Text
-widget, the function gtk_text_insert is used, which also allows us to
-specify background and foreground colors and a font for the text.
+    GtkWidget *window;
+    GtkWidget *menu;
+    GtkWidget *menu_bar;
+    GtkWidget *root_menu;
+    GtkWidget *menu_items;
+    GtkWidget *vbox;
+    GtkWidget *button;
+    char buf[128];
+    int i;
 
-<tscreen><verb>
-void gtk_text_insert( GtkText    *text,
-                      GdkFont    *font,
-                      GdkColor   *fore,
-                      GdkColor   *back,
-                      const char *chars,
-                      gint        length );
-</verb></tscreen>
+    gtk_init (&amp;argc, &amp;argv);
 
-Passing a value of <tt/NULL/ in as the value for the foreground color,
-background colour or font will result in the values set within the widget
-style to be used. Using a value of <tt/-1/ for the length parameter will
-result in the whole of the text string given being inserted.
+    /* create a new window */
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
+    gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
+    gtk_signal_connect(GTK_OBJECT (window), "delete_event",
+                       (GtkSignalFunc) gtk_main_quit, NULL);
 
-The text widget is one of the few within GTK that redraws itself
-dynamically, outside of the gtk_main function. This means that all changes
-to the contents of the text widget take effect immediately. This may be
-undesirable when performing multiple changes to the text widget. In order
-to allow us to perform multiple updates to the text widget without it
-continuously redrawing, we can freeze the widget, which temporarily stops
-it from automatically redrawing itself every time it is changed. We can
-then thaw the widget after our updates are complete.
+    /* Init the menu-widget, and remember -- never
+     * gtk_show_widget() the menu widget!! 
+     * This is the menu that holds the menu items, the one that
+     * will pop up when you click on the "Root Menu" in the app */
+    menu = gtk_menu_new();
 
-The following two functions perform this freeze and thaw action:
+    /* Next we make a little loop that makes three menu-entries for "test-menu".
+     * Notice the call to gtk_menu_append.  Here we are adding a list of
+     * menu items to our menu.  Normally, we'd also catch the "clicked"
+     * signal on each of the menu items and setup a callback for it,
+     * but it's omitted here to save space. */
 
-<tscreen><verb>
-void gtk_text_freeze( GtkText *text );
+    for(i = 0; i < 3; i++)
+        {
+            /* Copy the names to the buf. */
+            sprintf(buf, "Test-undermenu - %d", i);
 
-void gtk_text_thaw( GtkText *text );         
-</verb></tscreen>
+            /* Create a new menu-item with a name... */
+            menu_items = gtk_menu_item_new_with_label(buf);
 
-Text is deleted from the text widget relative to the current insertion
-point by the following two functions. The return value is a TRUE or
-FALSE indicator of whether the operation was successful.
+            /* ...and add it to the menu. */
+            gtk_menu_append(GTK_MENU (menu), menu_items);
 
-<tscreen><verb>
-gint gtk_text_backward_delete( GtkText *text,
-                               guint    nchars );
+           /* Do something interesting when the menuitem is selected */
+           gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
+               GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
 
-gint gtk_text_forward_delete ( GtkText *text,
-                               guint    nchars );
-</verb></tscreen>
+            /* Show the widget */
+            gtk_widget_show(menu_items);
+        }
 
-If you want to retrieve the contents of the text widget, then the macro 
-<tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the character at
-position <tt/index/ within the text widget <tt/t/.
+    /* This is the root menu, and will be the label
+     * displayed on the menu bar.  There won't be a signal handler attached,
+     * as it only pops up the rest of the menu when pressed. */
+    root_menu = gtk_menu_item_new_with_label("Root Menu");
 
-To retrieve larger blocks of text, we can use the function
+    gtk_widget_show(root_menu);
 
-<tscreen><verb>
-gchar *gtk_editable_get_chars( GtkEditable *editable,
-                               gint         start_pos,
-                               gint         end_pos );   
-</verb></tscreen>
+    /* Now we specify that we want our newly created "menu" to be the menu
+     * for the "root menu" */
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
 
-This is a function of the parent class of the text widget. A value of -1 as
-<tt/end_pos/ signifies the end of the text. The index of the text starts at 0.
+    /* A vbox to put a menu and a button in: */
+    vbox = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+    gtk_widget_show(vbox);
 
-The function allocates a new chunk of memory for the text block, so don't forget
-to free it with a call to g_free when you have finished with it.
-<!-- ----------------------------------------------------------------- -->
-<sect1>Keyboard Shortcuts
-<p>
-The text widget has a number of pre-installed keyboard shotcuts for common
-editing, motion and selection functions. These are accessed using Control
-and Alt key combinations.
+    /* Create a menu-bar to hold the menus and add it to our main window */
+    menu_bar = gtk_menu_bar_new();
+    gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
+    gtk_widget_show(menu_bar);
 
-In addition to these, holding down the Control key whilst using cursor key
-movement will move the cursor by words rather than characters. Holding down
-Shift whilst using cursor movement will extend the selection.
+    /* Create a button to which to attach menu as a popup */
+    button = gtk_button_new_with_label("press me");
+    gtk_signal_connect_object(GTK_OBJECT(button), "event",
+       GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
+    gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
+    gtk_widget_show(button);
 
-<sect2>Motion Shotcuts
-<p>
-<itemize>
-<item> Ctrl-A   Beginning of line
-<item> Ctrl-E   End of line
-<item> Ctrl-N   Next Line
-<item> Ctrl-P   Previous Line
-<item> Ctrl-B   Backward one character
-<item> Ctrl-F   Forward one character
-<item> Alt-B    Backward one word
-<item> Alt-F    Forward one word
-</itemize>
+    /* And finally we append the menu-item to the menu-bar -- this is the
+     * "root" menu-item I have been raving about =) */
+    gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
 
-<sect2>Editing Shortcuts
-<p>
-<itemize>
-<item> Ctrl-H   Delete Backward Character (Backspace)
-<item> Ctrl-D   Delete Forward Character (Delete)
-<item> Ctrl-W   Delete Backward Word
-<item> Alt-D    Delete Forward Word
-<item> Ctrl-K   Delete to end of line
-<item> Ctrl-U   Delete line
-</itemize>
+    /* always display the window as the last step so it all splashes on
+     * the screen at once. */
+    gtk_widget_show(window);
 
-<sect2>Selection Shortcuts
-<p>
-<itemize>
-<item> Ctrl-X   Cut to clipboard
-<item> Ctrl-C   Copy to clipboard
-<item> Ctrl-V   Paste from clipboard
-</itemize>
+    gtk_main ();
 
-<!-- ***************************************************************** -->
-<sect> Undocumented Widgets
-<!-- ***************************************************************** -->
-<p>
-These all require authors! :)  Please consider contributing to our tutorial.
+    return 0;
+}
 
-If you must use one of these widgets that are undocumented, I strongly
-suggest you take a look at their respective header files in the GTK
-distribution. GTK's function names are very descriptive.  Once you have an
-understanding of how things work, it's not difficult to figure out how to
-use a widget simply by looking at it's function declarations.  This, along
-with a few examples from others' code, and it should be no problem.
+/* Respond to a button-press by posting a menu passed in as widget.
+ *
+ * Note that the "widget" argument is the menu being posted, NOT
+ * the button that was pressed.
+ */
 
-When you do come to understand all the functions of a new undocumented
-widget, please consider writing a tutorial on it so others may benifit
-from your time.
+static gint button_press (GtkWidget *widget, GdkEvent *event)
+{
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Adjustments
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Toolbar
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Fixed Container
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Range Controls
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Curves
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Previews
-<p>
+    if (event->type == GDK_BUTTON_PRESS) {
+        GdkEventButton *bevent = (GdkEventButton *) event; 
+        gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
+                        bevent->button, bevent->time);
+        /* Tell calling code that we have handled this event; the buck
+         * stops here. */
+        return TRUE;
+    }
 
-(This may need to be rewritten to follow the style of the rest of the tutorial)
+    /* Tell calling code that we have not handled this event; pass it on. */
+    return FALSE;
+}
 
-<tscreen><verb>
 
-Previews serve a number of purposes in GIMP/GTK. The most important one is
-this. High quality images may take up to tens of megabytes of memory - easy!
-Any operation on an image that big is bound to take a long time. If it takes
-you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
-you make an error) to choose the desired modification, it make take you
-literally hours to make the right one - if you don't run out of memory
-first. People who have spent hours in color darkrooms know the feeling.
-Previews to the rescue!
+/* Print a string when a menu item is selected */
 
-But the annoyance of the delay is not the only issue. Oftentimes it is
-helpful to compare the Before and After versions side-by-side or at least
-back-to-back. If you're working with big images and 10 second delays,
-obtaining the Before and After impressions is, to say the least, difficult.
-For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
-out for most people, while back-to-back is more like back-to-1001, 1002,
-..., 1010-back! Previews to the rescue!
+static void menuitem_response (gchar *string)
+{
+    printf("%s\n", string);
+}
+/* example-end */
+</verb></tscreen>
 
-But there's more. Previews allow for side-by-side pre-previews. In other
-words, you write a plug-in (e.g. the filterpack simulation) which would have
-a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
-An approach like this acts as a sort of a preview palette and is very
-effective fow subtle changes. Let's go previews!
+You may also set a menu item to be insensitive and, using an accelerator
+table, bind keys to menu functions.
 
-There's more. For certain plug-ins real-time image-specific human
-intervention maybe necessary. In the SuperNova plug-in, for example, the
-user is asked to enter the coordinates of the center of the future
-supernova. The easiest way to do this, really, is to present the user with a
-preview and ask him to intereactively select the spot. Let's go previews!
+<!-- ----------------------------------------------------------------- -->
+<sect1>Using GtkMenuFactory
+<p>
+Now that we've shown you the hard way, here's how you do it using the
+gtk_menu_factory calls.
 
-Finally, a couple of misc uses. One can use previews even when not working
-with big images. For example, they are useful when rendering compicated
-patterns. (Just check out the venerable Diffraction plug-in + many other
-ones!) As another example, take a look at the colormap rotation plug-in
-(work in progress). You can also use previews for little logo's inside you
-plug-ins and even for an image of yourself, The Author. Let's go previews!
+<!-- ----------------------------------------------------------------- -->
+<sect1>Menu Factory Example
+<p>
+Here is an example using the GTK menu factory.  This is the first file,
+menufactory.h.  We keep a separate menufactory.c and mfmain.c because
+of the global variables used in the menufactory.c file.  
 
-When Not to Use Previews
+<tscreen><verb>
+/* example-start menu menufactory.h */
 
-Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
-previews only for rendered images!
+#ifndef __MENUFACTORY_H__
+#define __MENUFACTORY_H__
 
-Let's go previews!
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
-You can stick a preview into just about anything. In a vbox, an hbox, a
-table, a button, etc. But they look their best in tight frames around them.
-Previews by themselves do not have borders and look flat without them. (Of
-course, if the flat look is what you want...) Tight frames provide the
-necessary borders.
+void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
+void menus_create(GtkMenuEntry *entries, int nmenu_entries);
 
-                               [Image][Image]
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-Previews in many ways are like any other widgets in GTK (whatever that
-means) except they possess an addtional feature: they need to be filled with
-some sort of an image! First, we will deal exclusively with the GTK aspect
-of previews and then we'll discuss how to fill them.
+#endif /* __MENUFACTORY_H__ */
+/* example-end */
+</verb></tscreen>
 
-GtkWidget *preview!
+And here is the menufactory.c file.
 
-Without any ado:
+<tscreen><verb>
+/* example-start menu menufactory.c */
 
-                              /* Create a preview widget,
-                              set its size, an show it */
-GtkWidget *preview;
-preview=gtk_preview_new(GTK_PREVIEW_COLOR)
-                              /*Other option:
-                              GTK_PREVIEW_GRAYSCALE);*/
-gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
-gtk_widget_show(preview);
-my_preview_rendering_function(preview);
+#include <gtk/gtk.h>
+#include <strings.h>
 
-Oh yeah, like I said, previews look good inside frames, so how about:
+#include "mfmain.h"
 
-GtkWidget *create_a_preview(int        Width,
-                            int        Height,
-                            int        Colorfulness)
-{
-  GtkWidget *preview;
-  GtkWidget *frame;
-  
-  frame = gtk_frame_new(NULL);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
-  gtk_container_border_width (GTK_CONTAINER(frame),0);
-  gtk_widget_show(frame);
 
-  preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
-                                       :GTK_PREVIEW_GRAYSCALE);
-  gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
-  gtk_container_add(GTK_CONTAINER(frame),preview);
-  gtk_widget_show(preview);
+static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
+static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
+void menus_init(void);
+void menus_create(GtkMenuEntry * entries, int nmenu_entries);
 
-  my_preview_rendering_function(preview);
-  return frame;
-}
 
-That's my basic preview. This routine returns the "parent" frame so you can
-place it somewhere else in your interface. Of course, you can pass the
-parent frame to this routine as a parameter. In many situations, however,
-the contents of the preview are changed continually by your application. In
-this case you may want to pass a pointer to the preview to a
-"create_a_preview()" and thus have control of it later.
+/* this is the GtkMenuEntry structure used to create new menus.  The
+ * first member is the menu definition string.  The second, the
+ * default accelerator key used to access this menu function with
+ * the keyboard.  The third is the callback function to call when
+ * this menu item is selected (by the accelerator key, or with the
+ * mouse.) The last member is the data to pass to your callback function.
+ */
 
-One more important note that may one day save you a lot of time. Sometimes
-it is desirable to label you preview. For example, you may label the preview
-containing the original image as "Original" and the one containing the
-modified image as "Less Original". It might occure to you to pack the
-preview along with the appropriate label into a vbox. The unexpected caveat
-is that if the label is wider than the preview (which may happen for a
-variety of reasons unforseeable to you, from the dynamic decision on the
-size of the preview to the size of the font) the frame expands and no longer
-fits tightly over the preview. The same problem can probably arise in other
-situations as well.
+static GtkMenuEntry menu_items[] =
+{
+       {"<Main>/File/New", "<control>N", NULL, NULL},
+       {"<Main>/File/Open", "<control>O", NULL, NULL},
+       {"<Main>/File/Save", "<control>S", NULL, NULL},
+       {"<Main>/File/Save as", NULL, NULL, NULL},
+       {"<Main>/File/<separator>", NULL, NULL, NULL},
+       {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
+       {"<Main>/Options/Test", NULL, NULL, NULL}
+};
 
-                                   [Image]
+/* calculate the number of menu_item's */
+static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
 
-The solution is to place the preview and the label into a 2x1 table and by
-attaching them with the following paramters (this is one possible variations
-of course. The key is no GTK_FILL in the second attachment):
+static int initialize = TRUE;
+static GtkMenuFactory *factory = NULL;
+static GtkMenuFactory *subfactory[1];
+static GHashTable *entry_ht = NULL;
 
-gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
-                 0,
-                 GTK_EXPAND|GTK_FILL,
-                 0,0);
-gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
-                 GTK_EXPAND,
-                 GTK_EXPAND,
-                 0,0);
+void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
+{
+    if (initialize)
+           menus_init();
+    
+    if (menubar)
+           *menubar = subfactory[0]->widget;
+    if (table)
+           *table = subfactory[0]->table;
+}
+
+void menus_init(void)
+{
+    if (initialize) {
+       initialize = FALSE;
+       
+       factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
+       subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
+       
+       gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
+       menus_create(menu_items, nmenu_items);
+    }
+}
+
+void menus_create(GtkMenuEntry * entries, int nmenu_entries)
+{
+    char *accelerator;
+    int i;
+    
+    if (initialize)
+           menus_init();
+    
+    if (entry_ht)
+           for (i = 0; i < nmenu_entries; i++) {
+               accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
+               if (accelerator) {
+                   if (accelerator[0] == '\0')
+                           entries[i].accelerator = NULL;
+                   else
+                           entries[i].accelerator = accelerator;
+               }
+           }
+    gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
+    
+    for (i = 0; i < nmenu_entries; i++)
+           if (entries[i].widget) {
+               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
+                                  (GtkSignalFunc) menus_install_accel,
+                                  entries[i].path);
+               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
+                                  (GtkSignalFunc) menus_remove_accel,
+                                  entries[i].path);
+           }
+}
+
+static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
+{
+    char accel[64];
+    char *t1, t2[2];
+    
+    accel[0] = '\0';
+    if (modifiers & GDK_CONTROL_MASK)
+           strcat(accel, "<control>");
+    if (modifiers & GDK_SHIFT_MASK)
+           strcat(accel, "<shift>");
+    if (modifiers & GDK_MOD1_MASK)
+           strcat(accel, "<alt>");
+    
+    t2[0] = key;
+    t2[1] = '\0';
+    strcat(accel, t2);
+    
+    if (entry_ht) {
+       t1 = g_hash_table_lookup(entry_ht, path);
+       g_free(t1);
+    } else
+           entry_ht = g_hash_table_new(g_str_hash, g_str_equal);
+    
+    g_hash_table_insert(entry_ht, path, g_strdup(accel));
+    
+    return TRUE;
+}
+
+static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
+{
+    char *t;
+    
+    if (entry_ht) {
+       t = g_hash_table_lookup(entry_ht, path);
+       g_free(t);
+       
+       g_hash_table_insert(entry_ht, path, g_strdup(""));
+    }
+}
+
+void menus_set_sensitive(char *path, int sensitive)
+{
+    GtkMenuPath *menu_path;
+    
+    if (initialize)
+           menus_init();
+    
+    menu_path = gtk_menu_factory_find(factory, path);
+    if (menu_path)
+           gtk_widget_set_sensitive(menu_path->widget, sensitive);
+    else
+           g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path);
+}
+/* example-end */
+</verb></tscreen>
+
+And here's the mfmain.h
+
+<tscreen><verb>
+/* example-start menu mfmain.h */
+
+#ifndef __MFMAIN_H__
+#define __MFMAIN_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MFMAIN_H__ */
+/* example-end */
+</verb></tscreen>
+
+And mfmain.c
+
+<tscreen><verb>
+/* example-start menu mfmain.c */
+
+#include <gtk/gtk.h>
+
+#include "mfmain.h"
+#include "menufactory.h"
+
+
+int main(int argc, char *argv[])
+{
+    GtkWidget *window;
+    GtkWidget *main_vbox;
+    GtkWidget *menubar;
+    
+    GtkAcceleratorTable *accel;
+    
+    gtk_init(&amp;argc, &amp;argv);
+    
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_signal_connect(GTK_OBJECT(window), "destroy", 
+                      GTK_SIGNAL_FUNC(file_quit_cmd_callback), 
+                      "WM destroy");
+    gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
+    gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
+    
+    main_vbox = gtk_vbox_new(FALSE, 1);
+    gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
+    gtk_container_add(GTK_CONTAINER(window), main_vbox);
+    gtk_widget_show(main_vbox);
+    
+    get_main_menu(&amp;menubar, &amp;accel);
+    gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
+    gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
+    gtk_widget_show(menubar);
+    
+    gtk_widget_show(window);
+    gtk_main();
+    
+    return(0);
+}
+
+/* This is just to demonstrate how callbacks work when using the
+ * menufactory.  Often, people put all the callbacks from the menus
+ * in a separate file, and then have them call the appropriate functions
+ * from there.  Keeps it more organized. */
+void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
+{
+    g_print ("%s\n", (char *) data);
+    gtk_exit(0);
+}
+/* example-end */
+</verb></tscreen>
+
+And a makefile so it'll be easier to compile it.
+
+<tscreen><verb>
+# Makefile.mf
+
+CC      = gcc
+PROF    = -g
+C_FLAGS =  -Wall $(PROF) -L/usr/local/include -DDEBUG
+L_FLAGS =  $(PROF) -L/usr/X11R6/lib -L/usr/local/lib 
+L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
+PROGNAME = menufactory
+
+O_FILES = menufactory.o mfmain.o
+
+$(PROGNAME): $(O_FILES)
+       rm -f $(PROGNAME)
+       $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
+
+.c.o: 
+       $(CC) -c $(C_FLAGS) $<
+
+clean: 
+       rm -f core *.o $(PROGNAME) nohup.out
+distclean: clean 
+       rm -f *~
+</verb></tscreen>
+
+For now, there's only this example.  An explanation and lots 'o' comments
+will follow later.
+
+<!-- ***************************************************************** -->
+<sect> Text Widget
+<!-- ***************************************************************** -->
+<p>
+The Text widget allows multiple lines of text to be displayed and edited.
+It supports both multi-colored and multi-font text, allowing them to be
+mixed in any way we wish. It also has a wide set of key based text editing
+commands, which are compatible with Emacs.
+
+The text widget supports full cut-and-paste facilities, including the use
+of double- and triple-click to select a word and a whole line, respectively.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Creating and Configuring a Text box
+<p>
+There is only one function for creating a new Text widget.
+<tscreen><verb>
+GtkWidget *gtk_text_new( GtkAdjustment *hadj,
+                         GtkAdjustment *vadj );
+</verb></tscreen>
+
+The arguments allow us to give the Text widget pointers to Adjustments
+that can be used to track the viewing position of the widget. Passing NULL
+values to either or both of these arguments will cause the gtk_text_new
+function to create it's own.
+
+<tscreen><verb>
+void gtk_text_set_adjustments( GtkText       *text,
+                               GtkAdjustment *hadj,
+                               GtkAdjustment *vadj );
+</verb></tscreen>
+
+The above function allows the horizontal and vertical adjustments of a
+Text widget to be changed at any time.
+
+The text widget will not automatically create it's own scrollbars when
+the amount of text to be displayed is too long for the display window. We
+therefore have to create and add them to the display layout ourselves.
+
+<tscreen><verb>
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
+  gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
+  gtk_widget_show (vscrollbar);
+</verb></tscreen>
+
+The above code snippet creates a new vertical scrollbar, and attaches
+it to the vertical adjustment of the text widget, <tt/text/. It then packs
+it into a box in the normal way.
+
+Note, currently the GtkText widget does not support horizontal scrollbars.
+
+There are two main ways in which a Text widget can be used: to allow the
+user to edit a body of text, or to allow us to display multiple lines of
+text to the user. In order for us to switch between these modes of
+operation, the text widget has the following function:
+
+<tscreen><verb>
+void gtk_text_set_editable( GtkText *text,
+                            gint     editable );
+</verb></tscreen>
+
+The <tt/editable/ argument is a TRUE or FALSE value that specifies whether
+the user is permitted to edit the contents of the Text widget. When the
+text widget is editable, it will display a cursor at the current insertion
+point.
+
+You are not, however, restricted to just using the text widget in these
+two modes. You can toggle the editable state of the text widget at any
+time, and can insert text at any time.
+
+The text widget wraps lines of text that are too long to
+fit onto a single line of the display window. It's default behaviour is
+to break words across line breaks. This can be changed using the next
+function:
+
+<tscreen><verb>
+void gtk_text_set_word_wrap( GtkText *text,
+                             gint     word_wrap );
+</verb></tscreen>
+
+Using this function allows us to specify that the text widget should
+wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
+TRUE or FALSE value.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Text Manipulation
+<P>
+The current insertion point of a Text widget can be set using
+<tscreen><verb>
+void gtk_text_set_point( GtkText *text,
+                         guint    index );
+</verb></tscreen>
+
+where <tt/index/ is the position to set the insertion point.
+
+Analogous to this is the function for getting the current insertion point:
+
+<tscreen><verb>
+guint gtk_text_get_point( GtkText *text );
+</verb></tscreen>
+
+A function that is useful in combination with the above two functions is
+
+<tscreen><verb>
+guint gtk_text_get_length( GtkText *text );
+</verb></tscreen>
+
+which returns the current length of the Text widget. The length is the
+number of characters that are within the text block of the widget,
+including characters such as carriage-return, which marks the end of lines.
+
+In order to insert text at the current insertion point of a Text
+widget, the function gtk_text_insert is used, which also allows us to
+specify background and foreground colors and a font for the text.
+
+<tscreen><verb>
+void gtk_text_insert( GtkText    *text,
+                      GdkFont    *font,
+                      GdkColor   *fore,
+                      GdkColor   *back,
+                      const char *chars,
+                      gint        length );
+</verb></tscreen>
+
+Passing a value of <tt/NULL/ in as the value for the foreground color,
+background colour or font will result in the values set within the widget
+style to be used. Using a value of <tt/-1/ for the length parameter will
+result in the whole of the text string given being inserted.
+
+The text widget is one of the few within GTK that redraws itself
+dynamically, outside of the gtk_main function. This means that all changes
+to the contents of the text widget take effect immediately. This may be
+undesirable when performing multiple changes to the text widget. In order
+to allow us to perform multiple updates to the text widget without it
+continuously redrawing, we can freeze the widget, which temporarily stops
+it from automatically redrawing itself every time it is changed. We can
+then thaw the widget after our updates are complete.
+
+The following two functions perform this freeze and thaw action:
+
+<tscreen><verb>
+void gtk_text_freeze( GtkText *text );
+
+void gtk_text_thaw( GtkText *text );         
+</verb></tscreen>
+
+Text is deleted from the text widget relative to the current insertion
+point by the following two functions. The return value is a TRUE or
+FALSE indicator of whether the operation was successful.
+
+<tscreen><verb>
+gint gtk_text_backward_delete( GtkText *text,
+                               guint    nchars );
+
+gint gtk_text_forward_delete ( GtkText *text,
+                               guint    nchars );
+</verb></tscreen>
+
+If you want to retrieve the contents of the text widget, then the macro 
+<tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the character at
+position <tt/index/ within the text widget <tt/t/.
+
+To retrieve larger blocks of text, we can use the function
+
+<tscreen><verb>
+gchar *gtk_editable_get_chars( GtkEditable *editable,
+                               gint         start_pos,
+                               gint         end_pos );   
+</verb></tscreen>
+
+This is a function of the parent class of the text widget. A value of -1 as
+<tt/end_pos/ signifies the end of the text. The index of the text starts at 0.
+
+The function allocates a new chunk of memory for the text block, so don't forget
+to free it with a call to g_free when you have finished with it.
+<!-- ----------------------------------------------------------------- -->
+<sect1>Keyboard Shortcuts
+<p>
+The text widget has a number of pre-installed keyboard shotcuts for common
+editing, motion and selection functions. These are accessed using Control
+and Alt key combinations.
+
+In addition to these, holding down the Control key whilst using cursor key
+movement will move the cursor by words rather than characters. Holding down
+Shift whilst using cursor movement will extend the selection.
+
+<sect2>Motion Shotcuts
+<p>
+<itemize>
+<item> Ctrl-A   Beginning of line
+<item> Ctrl-E   End of line
+<item> Ctrl-N   Next Line
+<item> Ctrl-P   Previous Line
+<item> Ctrl-B   Backward one character
+<item> Ctrl-F   Forward one character
+<item> Alt-B    Backward one word
+<item> Alt-F    Forward one word
+</itemize>
+
+<sect2>Editing Shortcuts
+<p>
+<itemize>
+<item> Ctrl-H   Delete Backward Character (Backspace)
+<item> Ctrl-D   Delete Forward Character (Delete)
+<item> Ctrl-W   Delete Backward Word
+<item> Alt-D    Delete Forward Word
+<item> Ctrl-K   Delete to end of line
+<item> Ctrl-U   Delete line
+</itemize>
+
+<sect2>Selection Shortcuts
+<p>
+<itemize>
+<item> Ctrl-X   Cut to clipboard
+<item> Ctrl-C   Copy to clipboard
+<item> Ctrl-V   Paste from clipboard
+</itemize>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>A GtkText Example
+<p>
+<tscreen><verb>
+/* example-start text text.c */
+
+/* text.c */
+
+#include <stdio.h>
+#include <gtk/gtk.h>
+
+void text_toggle_editable (GtkWidget *checkbutton,
+                          GtkWidget *text)
+{
+  gtk_text_set_editable(GTK_TEXT(text),
+                       GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void text_toggle_word_wrap (GtkWidget *checkbutton,
+                           GtkWidget *text)
+{
+  gtk_text_set_word_wrap(GTK_TEXT(text),
+                        GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void close_application( GtkWidget *widget, gpointer data )
+{
+       gtk_main_quit();
+}
+
+int main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *hbox;
+  GtkWidget *button;
+  GtkWidget *check;
+  GtkWidget *separator;
+  GtkWidget *table;
+  GtkWidget *vscrollbar;
+  GtkWidget *text;
+  GdkColormap *cmap;
+  GdkColor colour;
+  GdkFont *fixed_font;
+
+  FILE *infile;
+
+  gtk_init (&amp;argc, &amp;argv);
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_usize (window, 600, 500);
+  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
+  gtk_container_border_width (GTK_CONTAINER (window), 0);
+  
+  
+  box1 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), box1);
+  gtk_widget_show (box1);
+  
+  
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
+  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+  gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
+  gtk_widget_show (table);
+  
+  /* Create the GtkText widget */
+  text = gtk_text_new (NULL, NULL);
+  gtk_text_set_editable (GTK_TEXT (text), TRUE);
+  gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (text);
+
+  /* Add a vertical scrollbar to the GtkText widget */
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+  gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+                   GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (vscrollbar);
+
+  /* Get the system colour map and allocate the colour red */
+  cmap = gdk_colormap_get_system();
+  colour.red = 0xffff;
+  colour.green = 0;
+  colour.blue = 0;
+  if (!gdk_color_alloc(cmap, &amp;colour)) {
+    g_error("couldn't allocate colour");
+  }
+
+  /* Load a fixed font */
+  fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
+
+  /* Realizing a widget creates a window for it, ready for us to insert some text */
+  gtk_widget_realize (text);
+
+  /* Freeze the text widget, ready for multiple updates */
+  gtk_text_freeze (GTK_TEXT (text));
+  
+  /* Insert some coloured text */
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+                  "Supports ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;colour, NULL,
+                  "colored ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+                  "text and different ", -1);
+  gtk_text_insert (GTK_TEXT (text), fixed_font, &amp;text->style->black, NULL,
+                  "fonts\n\n", -1);
+  
+  /* Load the file text.c into the text window */
+
+  infile = fopen("text.c", "r");
+  
+  if (infile) {
+    char buffer[1024];
+    int nchars;
+    
+    while (1)
+      {
+       nchars = fread(buffer, 1, 1024, infile);
+       gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
+                        NULL, buffer, nchars);
+       
+       if (nchars < 1024)
+         break;
+      }
+    
+    fclose (infile);
+  }
+
+  /* Thaw the text widget, allowing the updates to become visible */  
+  gtk_text_thaw (GTK_TEXT (text));
+  
+  hbox = gtk_hbutton_box_new ();
+  gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  check = gtk_check_button_new_with_label("Editable");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_editable), text);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
+  gtk_widget_show (check);
+  check = gtk_check_button_new_with_label("Wrap Words");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
+  gtk_widget_show (check);
+
+  separator = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+  gtk_widget_show (separator);
+
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  button = gtk_button_new_with_label ("close");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+  gtk_widget_grab_default (button);
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+  
+  return 0;       
+}
+/* example-end */
+</verb></tscreen>
+
+
+<!-- ***************************************************************** -->
+<sect> Undocumented Widgets
+<!-- ***************************************************************** -->
+<p>
+These all require authors! :)  Please consider contributing to our tutorial.
+
+If you must use one of these widgets that are undocumented, I strongly
+suggest you take a look at their respective header files in the GTK
+distribution. GTK's function names are very descriptive.  Once you have an
+understanding of how things work, it's not difficult to figure out how to
+use a widget simply by looking at it's function declarations.  This, along
+with a few examples from others' code, and it should be no problem.
+
+When you do come to understand all the functions of a new undocumented
+widget, please consider writing a tutorial on it so others may benifit
+from your time.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Adjustments
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Toolbar
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Fixed Container
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Range Controls
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Curves
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Previews
+<p>
+
+(This may need to be rewritten to follow the style of the rest of the tutorial)
+
+<tscreen><verb>
+
+Previews serve a number of purposes in GIMP/GTK. The most important one is
+this. High quality images may take up to tens of megabytes of memory - easy!
+Any operation on an image that big is bound to take a long time. If it takes
+you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
+you make an error) to choose the desired modification, it make take you
+literally hours to make the right one - if you don't run out of memory
+first. People who have spent hours in color darkrooms know the feeling.
+Previews to the rescue!
+
+But the annoyance of the delay is not the only issue. Oftentimes it is
+helpful to compare the Before and After versions side-by-side or at least
+back-to-back. If you're working with big images and 10 second delays,
+obtaining the Before and After impressions is, to say the least, difficult.
+For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
+out for most people, while back-to-back is more like back-to-1001, 1002,
+..., 1010-back! Previews to the rescue!
+
+But there's more. Previews allow for side-by-side pre-previews. In other
+words, you write a plug-in (e.g. the filterpack simulation) which would have
+a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
+An approach like this acts as a sort of a preview palette and is very
+effective fow subtle changes. Let's go previews!
+
+There's more. For certain plug-ins real-time image-specific human
+intervention maybe necessary. In the SuperNova plug-in, for example, the
+user is asked to enter the coordinates of the center of the future
+supernova. The easiest way to do this, really, is to present the user with a
+preview and ask him to intereactively select the spot. Let's go previews!
+
+Finally, a couple of misc uses. One can use previews even when not working
+with big images. For example, they are useful when rendering compicated
+patterns. (Just check out the venerable Diffraction plug-in + many other
+ones!) As another example, take a look at the colormap rotation plug-in
+(work in progress). You can also use previews for little logo's inside you
+plug-ins and even for an image of yourself, The Author. Let's go previews!
+
+When Not to Use Previews
+
+Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
+previews only for rendered images!
+
+Let's go previews!
+
+You can stick a preview into just about anything. In a vbox, an hbox, a
+table, a button, etc. But they look their best in tight frames around them.
+Previews by themselves do not have borders and look flat without them. (Of
+course, if the flat look is what you want...) Tight frames provide the
+necessary borders.
+
+                               [Image][Image]
+
+Previews in many ways are like any other widgets in GTK (whatever that
+means) except they possess an addtional feature: they need to be filled with
+some sort of an image! First, we will deal exclusively with the GTK aspect
+of previews and then we'll discuss how to fill them.
+
+GtkWidget *preview!
+
+Without any ado:
+
+                              /* Create a preview widget,
+                              set its size, an show it */
+GtkWidget *preview;
+preview=gtk_preview_new(GTK_PREVIEW_COLOR)
+                              /*Other option:
+                              GTK_PREVIEW_GRAYSCALE);*/
+gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
+gtk_widget_show(preview);
+my_preview_rendering_function(preview);
+
+Oh yeah, like I said, previews look good inside frames, so how about:
+
+GtkWidget *create_a_preview(int        Width,
+                            int        Height,
+                            int        Colorfulness)
+{
+  GtkWidget *preview;
+  GtkWidget *frame;
+  
+  frame = gtk_frame_new(NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  gtk_container_border_width (GTK_CONTAINER(frame),0);
+  gtk_widget_show(frame);
+
+  preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
+                                       :GTK_PREVIEW_GRAYSCALE);
+  gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
+  gtk_container_add(GTK_CONTAINER(frame),preview);
+  gtk_widget_show(preview);
+
+  my_preview_rendering_function(preview);
+  return frame;
+}
+
+That's my basic preview. This routine returns the "parent" frame so you can
+place it somewhere else in your interface. Of course, you can pass the
+parent frame to this routine as a parameter. In many situations, however,
+the contents of the preview are changed continually by your application. In
+this case you may want to pass a pointer to the preview to a
+"create_a_preview()" and thus have control of it later.
+
+One more important note that may one day save you a lot of time. Sometimes
+it is desirable to label you preview. For example, you may label the preview
+containing the original image as "Original" and the one containing the
+modified image as "Less Original". It might occure to you to pack the
+preview along with the appropriate label into a vbox. The unexpected caveat
+is that if the label is wider than the preview (which may happen for a
+variety of reasons unforseeable to you, from the dynamic decision on the
+size of the preview to the size of the font) the frame expands and no longer
+fits tightly over the preview. The same problem can probably arise in other
+situations as well.
+
+                                   [Image]
+
+The solution is to place the preview and the label into a 2x1 table and by
+attaching them with the following paramters (this is one possible variations
+of course. The key is no GTK_FILL in the second attachment):
+
+gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
+                 0,
+                 GTK_EXPAND|GTK_FILL,
+                 0,0);
+gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
+                 GTK_EXPAND,
+                 GTK_EXPAND,
+                 0,0);
 
 
 And here's the result:
 
-                                   [Image]
+                                   [Image]
+
+Misc
+
+Making a preview clickable is achieved most easily by placing it in a
+button. It also adds a nice border around the preview and you may not even
+need to place it in a frame. See the Filter Pack Simulation plug-in for an
+example.
+
+This is pretty much it as far as GTK is concerned.
+
+Filling In a Preview
+
+In order to familiarize ourselves with the basics of filling in previews,
+let's create the following pattern (contrived by trial and error):
+
+                                   [Image]
+
+void
+my_preview_rendering_function(GtkWidget     *preview)
+{
+#define SIZE 100
+#define HALF (SIZE/2)
+
+  guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
+  gint i, j;                             /* Coordinates    */
+  double r, alpha, x, y;
+
+  if (preview==NULL) return; /* I usually add this when I want */
+                             /* to avoid silly crashes. You    */
+                             /* should probably make sure that */
+                             /* everything has been nicely     */
+                             /* initialized!                   */
+  for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape?  */
+                                         /* glib.h contains ABS(x).   */
+        row[i*3+0] = sqrt(1-r)*255;      /* Define Red                */
+        row[i*3+1] = 128;                /* Define Green              */
+        row[i*3+2] = 224;                /* Define Blue               */
+      }                                  /* "+0" is for alignment!    */
+      else {
+        row[i*3+0] = r*255;
+        row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
+        row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
+      }
+    }
+    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
+    /* Insert "row" into "preview" starting at the point with  */
+    /* coordinates (0,j) first column, j_th row extending SIZE */
+    /* pixels to the right */
+  }
+
+  free(row); /* save some space */
+  gtk_widget_draw(preview,NULL); /* what does this do? */
+  gdk_flush(); /* or this? */
+}
+
+Non-GIMP users can have probably seen enough to do a lot of things already.
+For the GIMP users I have a few pointers to add.
+
+Image Preview
+
+It is probably wize to keep a reduced version of the image around with just
+enough pixels to fill the preview. This is done by selecting every n'th
+pixel where n is the ratio of the size of the image to the size of the
+preview. All further operations (including filling in the previews) are then
+performed on the reduced number of pixels only. The following is my
+implementation of reducing the image. (Keep in mind that I've had only basic
+C!)
+
+(UNTESTED CODE ALERT!!!)
+
+typedef struct {
+  gint      width;
+  gint      height;
+  gint      bbp;
+  guchar    *rgb;
+  guchar    *mask;
+} ReducedImage;
+
+enum {
+  SELECTION_ONLY,
+  SELCTION_IN_CONTEXT,
+  ENTIRE_IMAGE
+};
+
+ReducedImage *Reduce_The_Image(GDrawable *drawable,
+                               GDrawable *mask,
+                               gint LongerSize,
+                               gint Selection)
+{
+  /* This function reduced the image down to the the selected preview size */
+  /* The preview size is determine by LongerSize, i.e. the greater of the  */
+  /* two dimentions. Works for RGB images only!                            */
+  gint RH, RW;          /* Reduced height and reduced width                */
+  gint width, height;   /* Width and Height of the area being reduced      */
+  gint bytes=drawable->bpp;
+  ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
+
+  guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
+  gint i, j, whichcol, whichrow, x1, x2, y1, y2;
+  GPixelRgn srcPR, srcMask;
+  gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire  */
+                             /* image.                                     */
+
+  gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
+  width  = x2-x1;
+  height = y2-y1;
+  /* If there's a SELECTION, we got its bounds!)
+
+  if (width != drawable->width &amp;&amp; height != drawable->height)
+    NoSelectionMade=FALSE;
+  /* Become aware of whether the user has made an active selection   */
+  /* This will become important later, when creating a reduced mask. */
+
+  /* If we want to preview the entire image, overrule the above!  */
+  /* Of course, if no selection has been made, this does nothing! */
+  if (Selection==ENTIRE_IMAGE) {
+    x1=0;
+    x2=drawable->width;
+    y1=0;
+    y2=drawable->height;
+  }
+
+  /* If we want to preview a selection with some surronding area we */
+  /* have to expand it a little bit. Consider it a bit of a riddle. */
+  if (Selection==SELECTION_IN_CONTEXT) {
+    x1=MAX(0,                x1-width/2.0);
+    x2=MIN(drawable->width,  x2+width/2.0);
+    y1=MAX(0,                y1-height/2.0);
+    y2=MIN(drawable->height, y2+height/2.0);
+  }
+
+  /* How we can determine the width and the height of the area being */
+  /* reduced.                                                        */
+  width  = x2-x1;
+  height = y2-y1;
+
+  /* The lines below determine which dimension is to be the longer   */
+  /* side. The idea borrowed from the supernova plug-in. I suspect I */
+  /* could've thought of it myself, but the truth must be told.      */
+  /* Plagiarism stinks!                                               */
+  if (width>height) {
+    RW=LongerSize;
+    RH=(float) height * (float) LongerSize/ (float) width;
+  }
+  else {
+    RH=LongerSize;
+    RW=(float)width * (float) LongerSize/ (float) height;
+  }
+
+  /* The intire image is stretched into a string! */
+  tempRGB   = (guchar *) malloc(RW*RH*bytes);
+  tempmask  = (guchar *) malloc(RW*RH);
+
+  gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
+  gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height, FALSE, FALSE);
+
+  /* Grab enough to save a row of image and a row of mask. */
+  src_row       = (guchar *) malloc (width*bytes);
+  src_mask_row  = (guchar *) malloc (width);
+
+  for (i=0; i < RH; i++) {
+    whichrow=(float)i*(float)height/(float)RH;
+    gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
+    gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
+
+    for (j=0; j < RW; j++) {
+      whichcol=(float)j*(float)width/(float)RW;
+
+      /* No selection made = each point is completely selected! */
+      if (NoSelectionMade)
+        tempmask[i*RW+j]=255;
+      else
+        tempmask[i*RW+j]=src_mask_row[whichcol];
+
+      /* Add the row to the one long string which now contains the image! */
+      tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
+      tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
+      tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
+
+      /* Hold on to the alpha as well */
+      if (bytes==4)
+        tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
+    }
+  }
+  temp->bpp=bytes;
+  temp->width=RW;
+  temp->height=RH;
+  temp->rgb=tempRGB;
+  temp->mask=tempmask;
+  return temp;
+}
+
+The following is a preview function which used the same ReducedImage type!
+Note that it uses fakes transparancy (if one is present by means of
+fake_transparancy which is defined as follows:
+
+gint fake_transparency(gint i, gint j)
+{
+  if ( ((i%20)- 10) * ((j%20)- 10)>0   )
+    return 64;
+  else
+    return 196;
+}
+
+Now here's the preview function:
+
+void
+my_preview_render_function(GtkWidget     *preview,
+                           gint          changewhat,
+                           gint          changewhich)
+{
+  gint Inten, bytes=drawable->bpp;
+  gint i, j, k;
+  float partial;
+  gint RW=reduced->width;
+  gint RH=reduced->height;
+  guchar *row=malloc(bytes*RW);;
+
+
+  for (i=0; i < RH; i++) {
+    for (j=0; j < RW; j++) {
+
+      row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
+      row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
+      row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
+
+      if (bytes==4)
+        for (k=0; k<3; k++) {
+          float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
+          row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
+        }
+    }
+    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
+  }
+
+  free(a);
+  gtk_widget_draw(preview,NULL);
+  gdk_flush();
+}
+
+Applicable Routines
+
+guint           gtk_preview_get_type           (void);
+/* No idea */
+void            gtk_preview_uninit             (void);
+/* No idea */
+GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
+/* Described above */
+void            gtk_preview_size               (GtkPreview      *preview,
+                                                gint             width,
+                                                gint             height);
+/* Allows you to resize an existing preview.    */
+/* Apparantly there's a bug in GTK which makes  */
+/* this process messy. A way to clean up a mess */
+/* is to manually resize the window containing  */
+/* the preview after resizing the preview.      */
+
+void            gtk_preview_put                (GtkPreview      *preview,
+                                                GdkWindow       *window,
+                                                GdkGC           *gc,
+                                                gint             srcx,
+                                                gint             srcy,
+                                                gint             destx,
+                                                gint             desty,
+                                                gint             width,
+                                                gint             height);
+/* No idea */
+
+void            gtk_preview_put_row            (GtkPreview      *preview,
+                                                guchar          *src,
+                                                guchar          *dest,
+                                                gint             x,
+                                                gint             y,
+                                                gint             w);
+/* No idea */
+
+void            gtk_preview_draw_row           (GtkPreview      *preview,
+                                                guchar          *data,
+                                                gint             x,
+                                                gint             y,
+                                                gint             w);
+/* Described in the text */
+
+void            gtk_preview_set_expand         (GtkPreview      *preview,
+                                                gint             expand);
+/* No idea */
+
+/* No clue for any of the below but    */
+/* should be standard for most widgets */
+void            gtk_preview_set_gamma          (double           gamma);
+void            gtk_preview_set_color_cube     (guint            nred_shades,
+                                                guint            ngreen_shades,
+                                                guint            nblue_shades,
+                                                guint            ngray_shades);
+void            gtk_preview_set_install_cmap   (gint             install_cmap);
+void            gtk_preview_set_reserved       (gint             nreserved);
+GdkVisual*      gtk_preview_get_visual         (void);
+GdkColormap*    gtk_preview_get_cmap           (void);
+GtkPreviewInfo* gtk_preview_get_info           (void);
+
+That's all, folks!
+
+</verb></tscreen>
+
+<!-- ***************************************************************** -->
+<sect>The EventBox Widget<label id="sec_The_EventBox_Widget">
+<!-- ***************************************************************** -->
+<p> 
+Some gtk widgets don't have associated X windows, so they just draw on 
+their parents. Because of this, they cannot recieve events
+and if they are incorrectly sized, they don't clip so you can get
+messy overwritting etc. If you require more from these widgets, the
+EventBox is for you.
+
+At first glance, the EventBox widget might appear to be totally
+useless. It draws nothing on the screen and responds to no
+events. However, it does serve a function - it provides an X window for
+its child widget. This is important as many GTK widgets do not
+have an associated X window. Not having an X window saves memory and
+improves performance, but also has some drawbacks. A widget without an
+X window cannot receive events, and does not perform any clipping on
+it's contents. Although the name <em/EventBox/ emphasizes the
+event-handling function, the widget can also be used for clipping. 
+(And more ... see the example below.)
+
+To create a new EventBox widget, use:
+
+<tscreen><verb>
+GtkWidget *gtk_event_box_new( void );
+</verb></tscreen>
+
+A child widget can then be added to this EventBox:
+
+<tscreen><verb>
+gtk_container_add( GTK_CONTAINER(event_box), widget );
+</verb></tscreen>
+
+The following example demonstrates both uses of an EventBox - a label
+is created that is clipped to a small box, and set up so that a
+mouse-click on the label causes the program to exit.
+
+<tscreen><verb>
+/* example-start eventbox eventbox.c */
+
+#include <gtk/gtk.h>
+
+int 
+main (int argc, char *argv[])
+{
+    GtkWidget *window;
+    GtkWidget *event_box;
+    GtkWidget *label;
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    
+    gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+    
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+    
+    gtk_container_border_width (GTK_CONTAINER (window), 10);
+    
+    /* Create an EventBox and add it to our toplevel window */
+    
+    event_box = gtk_event_box_new ();
+    gtk_container_add (GTK_CONTAINER(window), event_box);
+    gtk_widget_show (event_box);
+    
+    /* Create a long label */
+    
+    label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
+    gtk_container_add (GTK_CONTAINER (event_box), label);
+    gtk_widget_show (label);
+    
+    /* Clip it short. */
+    gtk_widget_set_usize (label, 110, 20);
+    
+    /* And bind an action to it */
+    gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
+    gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+    
+    /* Yet one more thing you need an X window for ... */
+    
+    gtk_widget_realize (event_box);
+    gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
+    
+    gtk_widget_show (window);
+    
+    gtk_main ();
+    
+    return 0;
+}
+/* example-end */
+</verb></tscreen>
+
+<!-- ***************************************************************** -->
+<sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
+<!-- ***************************************************************** -->
+<p>
+This describes the functions used to operate on widgets.  These can be used
+to set style, padding, size etc.
+
+(Maybe I should make a whole section on accelerators.)
+
+<tscreen><verb>
+void gtk_widget_install_accelerator( GtkWidget           *widget,
+                                     GtkAcceleratorTable *table,
+                                     gchar               *signal_name,
+                                     gchar                key,
+                                     guint8               modifiers );
+
+void gtk_widget_remove_accelerator ( GtkWidget           *widget,
+                                     GtkAcceleratorTable *table,
+                                     gchar               *signal_name);
+
+void gtk_widget_activate( GtkWidget *widget );
+
+void gtk_widget_set_name( GtkWidget *widget,
+                          gchar     *name );
+
+gchar *gtk_widget_get_name( GtkWidget *widget );
+
+void gtk_widget_set_sensitive( GtkWidget *widget,
+                               gint       sensitive );
+
+void gtk_widget_set_style( GtkWidget *widget,
+                           GtkStyle  *style );
+                                          
+GtkStyle *gtk_widget_get_style( GtkWidget *widget );
+
+GtkStyle *gtk_widget_get_default_style( void );
+
+void gtk_widget_set_uposition( GtkWidget *widget,
+                               gint       x,
+                               gint       y );
+
+void gtk_widget_set_usize( GtkWidget *widget,
+                           gint       width,
+                           gint       height );
+
+void gtk_widget_grab_focus( GtkWidget *widget );
+
+void gtk_widget_show( GtkWidget *widget );
+
+void gtk_widget_hide( GtkWidget *widget );
+</verb></tscreen>
+
+<!-- ***************************************************************** -->
+<sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
+<!-- ***************************************************************** -->
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Timeouts
+<p>
+You may be wondering how you make GTK do useful work when in gtk_main.
+Well, you have several options. Using the following functions you can
+create a timeout function that will be called every "interval"
+milliseconds.
+
+<tscreen><verb>
+gint gtk_timeout_add( guint32     interval,
+                      GtkFunction function,
+                      gpointer    data );
+</verb></tscreen>
+
+The first argument is the number of milliseconds between calls to your
+function.  The second argument is the function you wish to have called, and
+the third, the data passed to this callback function. The return value is
+an integer "tag" which may be used to stop the timeout by calling:
+
+<tscreen><verb>
+void gtk_timeout_remove( gint tag );
+</verb></tscreen>
+
+You may also stop the timeout function by returning zero or FALSE from
+your callback function. Obviously this means if you want your function to
+continue to be called, it should return a non-zero value, ie TRUE.
+
+The declaration of your callback should look something like this:
+
+<tscreen><verb>
+gint timeout_callback( gpointer data );
+</verb></tscreen>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Monitoring IO
+<p>
+Another nifty feature of GTK, is the ability to have it check for data on a
+file descriptor for you (as returned by open(2) or socket(2)). This is
+especially useful for networking applications. The function:
+
+<tscreen><verb>
+gint gdk_input_add( gint              source,
+                    GdkInputCondition condition,
+                    GdkInputFunction  function,
+                    gpointer          data );
+</verb></tscreen>
+
+Where the first argument is the file descriptor you wish to have watched,
+and the second specifies what you want GDK to look for.  This may be one of:
+
+<itemize>
+<item>GDK_INPUT_READ - Call your function when there is data ready for
+reading on your file descriptor.
+
+<item>GDK_INPUT_WRITE - Call your function when the file descriptor is
+ready for writing.
+</itemize>
+
+As I'm sure you've figured out already, the third argument is the function
+you wish to have called when the above conditions are satisfied, and the
+fourth is the data to pass to this function.
+
+The return value is a tag that may be used to stop GDK from monitoring this
+file descriptor using the following function.
+
+<tscreen><verb>
+void gdk_input_remove( gint tag );
+</verb></tscreen>
+
+The callback function should be declared as:
+
+<tscreen><verb>
+void input_callback( gpointer          data,
+                     gint              source, 
+                     GdkInputCondition condition );
+</verb></tscreen>
+
+Where <tt/source/ and <tt/condition/ are as specified above.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Idle Functions
+<p>
+<!-- Need to check on idle priorities - TRG -->
+What if you have a function you want called when nothing else is
+happening ?
+
+<tscreen><verb>
+gint gtk_idle_add( GtkFunction function,
+                   gpointer    data );
+</verb></tscreen>
+
+This causes GTK to call the specified function whenever nothing else is
+happening.
+
+<tscreen><verb>
+void gtk_idle_remove( gint tag );
+</verb></tscreen>
+
+I won't explain the meaning of the arguments as they follow very much like
+the ones above. The function pointed to by the first argument to
+gtk_idle_add will be called whenever the opportunity arises. As with the
+others, returning FALSE will stop the idle function from being called.
+
+<!-- ***************************************************************** -->
+<sect>Managing Selections
+<!-- ***************************************************************** -->
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Overview
+<p>
+One type of interprocess communication supported by GTK is
+<em>selections</em>. A selection identifies a chunk of data, for
+instance, a portion of text, selected by the user in some fashion, for
+instance, by dragging with the mouse. Only one application on a
+display, (the <em>owner</em> can own a particular selection at one
+time, so when a selection is claimed by one application, the previous
+owner must indicate to the user that selection has been
+relinquished. Other applications can request the contents of a
+selection in different forms, called <em>targets</em>. There can be
+any number of selections, but most X applications only handle one, the
+<em>primary selection</em>.
+
+In most cases, it isn't necessary for a GTK application to deal with
+selections itself. The standard widgets, such as the Entry widget,
+already have the capability to claim the selection when appropriate
+(e.g., when the user drags over text), and to retrieve the contents of
+the selection owned by another widget, or another application (e.g.,
+when the user clicks the second mouse button). However, there may be
+cases in which you want to give other widgets the ability to supply
+the selection, or you wish to retrieve targets not supported by
+default.
 
-Misc
+A fundamental concept needed to understand selection handling is that
+of the <em>atom</em>. An atom is an integer that uniquely identifies a
+string (on a certain display). Certain atoms are predefined by the X
+server, and in some cases there are constants in <tt>gtk.h</tt>
+corresponding to these atoms. For instance the constant
+<tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
+In other cases, you should use the functions
+<tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
+and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
+selections and targets are identifed by atoms.
 
-Making a preview clickable is achieved most easily by placing it in a
-button. It also adds a nice border around the preview and you may not even
-need to place it in a frame. See the Filter Pack Simulation plug-in for an
-example.
+<!-- ----------------------------------------------------------------- -->
+<sect1> Retrieving the selection
+<p>
+Retrieving the selection is an asynchronous process. To start the
+process, you call:
 
-This is pretty much it as far as GTK is concerned.
+<tscreen><verb>
+gint gtk_selection_convert( GtkWidget *widget, 
+                            GdkAtom    selection, 
+                            GdkAtom    target,
+                            guint32    time );
+</verb</tscreen>
 
-Filling In a Preview
+This <em>converts</em> the selection into the form specified by
+<tt/target/. If at all possible, the time field should be the time
+from the event that triggered the selection. This helps make sure that
+events occur in the order that the user requested them. However, if it
+is not available (for instance, if the conversion was triggered by
+a "clicked" signal), then you can use the constant
+<tt>GDK_CURRENT_TIME</tt>.
 
-In order to familiarize ourselves with the basics of filling in previews,
-let's create the following pattern (contrived by trial and error):
+When the selection owner responds to the request, a
+"selection_received" signal is sent to your application. The handler
+for this signal receives a pointer to a <tt>GtkSelectionData</tt>
+structure, which is defined as:
 
-                                   [Image]
+<tscreen><verb>
+struct _GtkSelectionData
+{
+  GdkAtom selection;
+  GdkAtom target;
+  GdkAtom type;
+  gint    format;
+  guchar *data;
+  gint    length;
+};
+</verb></tscreen>
+
+<tt>selection</tt> and <tt>target</tt> are the values you gave in your
+<tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
+identifies the type of data returned by the selection owner. Some
+possible values are "STRING", a string of latin-1 characters, "ATOM",
+a series of atoms, "INTEGER", an integer, etc. Most targets can only
+return one type. <tt/format/ gives the length of the units (for
+instance characters) in bits. Usually, you don't care about this when
+receiving data. <tt>data</tt> is a pointer to the returned data, and
+<tt>length</tt> gives the length of the returned data, in bytes. If
+<tt>length</tt> is negative, then an error occurred and the selection
+could not be retrieved. This might happen if no application owned the
+selection, or if you requested a target that the application didn't
+support. The buffer is actually guaranteed to be one byte longer than
+<tt>length</tt>; the extra byte will always be zero, so it isn't
+necessary to make a copy of strings just to null terminate them.
+
+In the following example, we retrieve the special target "TARGETS",
+which is a list of all targets into which the selection can be
+converted.
+
+<tscreen><verb>
+/* example-start selection gettargets.c */
+
+#include <gtk/gtk.h>
 
+void selection_received (GtkWidget *widget, 
+                        GtkSelectionData *selection_data, 
+                        gpointer data);
+
+/* Signal handler invoked when user clicks on the "Get Targets" button */
 void
-my_preview_rendering_function(GtkWidget     *preview)
+get_targets (GtkWidget *widget, gpointer data)
 {
-#define SIZE 100
-#define HALF (SIZE/2)
+  static GdkAtom targets_atom = GDK_NONE;
 
-  guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
-  gint i, j;                             /* Coordinates    */
-  double r, alpha, x, y;
+  /* Get the atom corresonding to the string "TARGETS" */
+  if (targets_atom == GDK_NONE)
+    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
 
-  if (preview==NULL) return; /* I usually add this when I want */
-                             /* to avoid silly crashes. You    */
-                             /* should probably make sure that */
-                             /* everything has been nicely     */
-                             /* initialized!                   */
-  for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape?  */
-                                         /* glib.h contains ABS(x).   */
-        row[i*3+0] = sqrt(1-r)*255;      /* Define Red                */
-        row[i*3+1] = 128;                /* Define Green              */
-        row[i*3+2] = 224;                /* Define Blue               */
-      }                                  /* "+0" is for alignment!    */
-      else {
-        row[i*3+0] = r*255;
-        row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
-        row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
-      }
+  /* And request the "TARGETS" target for the primary selection */
+  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
+                        GDK_CURRENT_TIME);
+}
+
+/* Signal handler called when the selections owner returns the data */
+void
+selection_received (GtkWidget *widget, GtkSelectionData *selection_data, 
+                   gpointer data)
+{
+  GdkAtom *atoms;
+  GList *item_list;
+  int i;
+
+  /* **** IMPORTANT **** Check to see if retrieval succeeded  */
+  if (selection_data->length < 0)
+    {
+      g_print ("Selection retrieval failed\n");
+      return;
     }
-    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
-    /* Insert "row" into "preview" starting at the point with  */
-    /* coordinates (0,j) first column, j_th row extending SIZE */
-    /* pixels to the right */
-  }
+  /* Make sure we got the data in the expected form */
+  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
+    {
+      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
+      return;
+    }
+  
+  /* Print out the atoms we received */
+  atoms = (GdkAtom *)selection_data->data;
 
-  free(row); /* save some space */
-  gtk_widget_draw(preview,NULL); /* what does this do? */
-  gdk_flush(); /* or this? */
+  item_list = NULL;
+  for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
+    {
+      char *name;
+      name = gdk_atom_name (atoms[i]);
+      if (name != NULL)
+       g_print ("%s\n",name);
+      else
+       g_print ("(bad atom)\n");
+    }
+
+  return;
 }
 
-Non-GIMP users can have probably seen enough to do a lot of things already.
-For the GIMP users I have a few pointers to add.
+int 
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *button;
+  
+  gtk_init (&amp;argc, &amp;argv);
 
-Image Preview
+  /* Create the toplevel window */
 
-It is probably wize to keep a reduced version of the image around with just
-enough pixels to fill the preview. This is done by selecting every n'th
-pixel where n is the ratio of the size of the image to the size of the
-preview. All further operations (including filling in the previews) are then
-performed on the reduced number of pixels only. The following is my
-implementation of reducing the image. (Keep in mind that I've had only basic
-C!)
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
 
-(UNTESTED CODE ALERT!!!)
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
 
-typedef struct {
-  gint      width;
-  gint      height;
-  gint      bbp;
-  guchar    *rgb;
-  guchar    *mask;
-} ReducedImage;
+  /* Create a button the user can click to get targets */
 
-enum {
-  SELECTION_ONLY,
-  SELCTION_IN_CONTEXT,
-  ENTIRE_IMAGE
-};
+  button = gtk_button_new_with_label ("Get Targets");
+  gtk_container_add (GTK_CONTAINER (window), button);
 
-ReducedImage *Reduce_The_Image(GDrawable *drawable,
-                               GDrawable *mask,
-                               gint LongerSize,
-                               gint Selection)
-{
-  /* This function reduced the image down to the the selected preview size */
-  /* The preview size is determine by LongerSize, i.e. the greater of the  */
-  /* two dimentions. Works for RGB images only!                            */
-  gint RH, RW;          /* Reduced height and reduced width                */
-  gint width, height;   /* Width and Height of the area being reduced      */
-  gint bytes=drawable->bpp;
-  ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
+  gtk_signal_connect (GTK_OBJECT(button), "clicked",
+                     GTK_SIGNAL_FUNC (get_targets), NULL);
+  gtk_signal_connect (GTK_OBJECT(button), "selection_received",
+                     GTK_SIGNAL_FUNC (selection_received), NULL);
 
-  guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
-  gint i, j, whichcol, whichrow, x1, x2, y1, y2;
-  GPixelRgn srcPR, srcMask;
-  gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire  */
-                             /* image.                                     */
+  gtk_widget_show (button);
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+/* example-end */
+</verb></tscreen>
 
-  gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
-  width  = x2-x1;
-  height = y2-y1;
-  /* If there's a SELECTION, we got its bounds!)
+<!-- ----------------------------------------------------------------- -->
+<sect1> Supplying the selection 
+<p>
+Supplying the selection is a bit more complicated. You must register 
+handlers that will be called when your selection is requested. For
+each selection/target pair you will handle, you make a call to:
 
-  if (width != drawable->width &amp;&amp; height != drawable->height)
-    NoSelectionMade=FALSE;
-  /* Become aware of whether the user has made an active selection   */
-  /* This will become important later, when creating a reduced mask. */
+<tscreen><verb>
+void gtk_selection_add_handler( GtkWidget            *widget, 
+                                GdkAtom               selection,
+                                GdkAtom               target,
+                                GtkSelectionFunction  function,
+                                GtkRemoveFunction     remove_func,
+                                gpointer              data );
+</verb></tscreen>
 
-  /* If we want to preview the entire image, overrule the above!  */
-  /* Of course, if no selection has been made, this does nothing! */
-  if (Selection==ENTIRE_IMAGE) {
-    x1=0;
-    x2=drawable->width;
-    y1=0;
-    y2=drawable->height;
-  }
+<tt/widget/, <tt/selection/, and <tt/target/ identify the requests
+this handler will manage.  <tt/remove_func/, if not
+NULL, will be called when the signal handler is removed. This is
+useful, for instance, for interpreted languages which need to
+keep track of a reference count for <tt/data/.
 
-  /* If we want to preview a selection with some surronding area we */
-  /* have to expand it a little bit. Consider it a bit of a riddle. */
-  if (Selection==SELECTION_IN_CONTEXT) {
-    x1=MAX(0,                x1-width/2.0);
-    x2=MIN(drawable->width,  x2+width/2.0);
-    y1=MAX(0,                y1-height/2.0);
-    y2=MIN(drawable->height, y2+height/2.0);
-  }
+The callback function has the signature:
 
-  /* How we can determine the width and the height of the area being */
-  /* reduced.                                                        */
-  width  = x2-x1;
-  height = y2-y1;
+<tscreen><verb>
+typedef void (*GtkSelectionFunction)( GtkWidget        *widget, 
+                                      GtkSelectionData *selection_data,
+                                      gpointer          data );
 
-  /* The lines below determine which dimension is to be the longer   */
-  /* side. The idea borrowed from the supernova plug-in. I suspect I */
-  /* could've thought of it myself, but the truth must be told.      */
-  /* Plagiarism stinks!                                               */
-  if (width>height) {
-    RW=LongerSize;
-    RH=(float) height * (float) LongerSize/ (float) width;
-  }
-  else {
-    RH=LongerSize;
-    RW=(float)width * (float) LongerSize/ (float) height;
-  }
+</verb></tscreen>
 
-  /* The intire image is stretched into a string! */
-  tempRGB   = (guchar *) malloc(RW*RH*bytes);
-  tempmask  = (guchar *) malloc(RW*RH);
+The GtkSelectionData is the same as above, but this time, we're
+responsible for filling in the fields <tt/type/, <tt/format/,
+<tt/data/, and <tt/length/. (The <tt/format/ field is actually
+important here - the X server uses it to figure out whether the data
+needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
+character - or 32 - <em/i.e./ a. integer.) This is done by calling the
+function:
 
-  gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
-  gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height, FALSE, FALSE);
+<tscreen><verb>
+void gtk_selection_data_set( GtkSelectionData *selection_data,
+                             GdkAtom           type,
+                             gint              format,
+                             guchar           *data,
+                             gint              length );
+</verb></tscreen>
 
-  /* Grab enough to save a row of image and a row of mask. */
-  src_row       = (guchar *) malloc (width*bytes);
-  src_mask_row  = (guchar *) malloc (width);
+This function takes care of properly making a copy of the data so that
+you don't have to worry about keeping it around. (You should not fill
+in the fields of the GtkSelectionData structure by hand.)
 
-  for (i=0; i < RH; i++) {
-    whichrow=(float)i*(float)height/(float)RH;
-    gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
-    gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
+When prompted by the user, you claim ownership of the selection by
+calling:
 
-    for (j=0; j < RW; j++) {
-      whichcol=(float)j*(float)width/(float)RW;
+<tscreen><verb>
+gint gtk_selection_owner_set( GtkWidget *widget,
+                              GdkAtom    selection,
+                              guint32    time );
+</verb></tscreen>
 
-      /* No selection made = each point is completely selected! */
-      if (NoSelectionMade)
-        tempmask[i*RW+j]=255;
-      else
-        tempmask[i*RW+j]=src_mask_row[whichcol];
+If another application claims ownership of the selection, you will
+receive a "selection_clear_event".
 
-      /* Add the row to the one long string which now contains the image! */
-      tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
-      tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
-      tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
+As an example of supplying the selection, the following program adds
+selection functionality to a toggle button. When the toggle button is
+depressed, the program claims the primary selection. The only target
+supported (aside from certain targets like "TARGETS" supplied by GTK
+itself), is the "STRING" target. When this target is requested, a
+string representation of the time is returned.
 
-      /* Hold on to the alpha as well */
-      if (bytes==4)
-        tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
-    }
-  }
-  temp->bpp=bytes;
-  temp->width=RW;
-  temp->height=RH;
-  temp->rgb=tempRGB;
-  temp->mask=tempmask;
-  return temp;
-}
+<tscreen><verb>
+/* example-start selection setselection.c */
 
-The following is a preview function which used the same ReducedImage type!
-Note that it uses fakes transparancy (if one is present by means of
-fake_transparancy which is defined as follows:
+#include <gtk/gtk.h>
+#include <time.h>
 
-gint fake_transparency(gint i, gint j)
+/* Callback when the user toggles the selection */
+void
+selection_toggled (GtkWidget *widget, gint *have_selection)
 {
-  if ( ((i%20)- 10) * ((j%20)- 10)>0   )
-    return 64;
+  if (GTK_TOGGLE_BUTTON(widget)->active)
+    {
+      *have_selection = gtk_selection_owner_set (widget,
+                                                GDK_SELECTION_PRIMARY,
+                                                GDK_CURRENT_TIME);
+      /* if claiming the selection failed, we return the button to
+        the out state */
+      if (!*have_selection)
+       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
+    }
   else
-    return 196;
+    {
+      if (*have_selection)
+       {
+         /* Before clearing the selection by setting the owner to NULL,
+            we check if we are the actual owner */
+         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
+                                    GDK_CURRENT_TIME);
+         *have_selection = FALSE;
+       }
+    }
 }
 
-Now here's the preview function:
-
-void
-my_preview_render_function(GtkWidget     *preview,
-                           gint          changewhat,
-                           gint          changewhich)
+/* Called when another application claims the selection */
+gint
+selection_clear (GtkWidget *widget, GdkEventSelection *event,
+                gint *have_selection)
 {
-  gint Inten, bytes=drawable->bpp;
-  gint i, j, k;
-  float partial;
-  gint RW=reduced->width;
-  gint RH=reduced->height;
-  guchar *row=malloc(bytes*RW);;
-
+  *have_selection = FALSE;
+  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
 
-  for (i=0; i < RH; i++) {
-    for (j=0; j < RW; j++) {
+  return TRUE;
+}
 
-      row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
-      row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
-      row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
+/* Supplies the current time as the selection. */
+void
+selection_handle (GtkWidget *widget, 
+                 GtkSelectionData *selection_data,
+                 gpointer data)
+{
+  gchar *timestr;
+  time_t current_time;
 
-      if (bytes==4)
-        for (k=0; k<3; k++) {
-          float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
-          row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
-        }
-    }
-    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
-  }
+  current_time = time (NULL);
+  timestr = asctime (localtime(&amp;current_time)); 
+  /* When we return a single string, it should not be null terminated.
+     That will be done for us */
 
-  free(a);
-  gtk_widget_draw(preview,NULL);
-  gdk_flush();
+  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
+                         8, timestr, strlen(timestr));
 }
 
-Applicable Routines
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
 
-guint           gtk_preview_get_type           (void);
-/* No idea */
-void            gtk_preview_uninit             (void);
-/* No idea */
-GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
-/* Described above */
-void            gtk_preview_size               (GtkPreview      *preview,
-                                                gint             width,
-                                                gint             height);
-/* Allows you to resize an existing preview.    */
-/* Apparantly there's a bug in GTK which makes  */
-/* this process messy. A way to clean up a mess */
-/* is to manually resize the window containing  */
-/* the preview after resizing the preview.      */
+  GtkWidget *selection_button;
 
-void            gtk_preview_put                (GtkPreview      *preview,
-                                                GdkWindow       *window,
-                                                GdkGC           *gc,
-                                                gint             srcx,
-                                                gint             srcy,
-                                                gint             destx,
-                                                gint             desty,
-                                                gint             width,
-                                                gint             height);
-/* No idea */
+  static int have_selection = FALSE;
+  
+  gtk_init (&amp;argc, &amp;argv);
 
-void            gtk_preview_put_row            (GtkPreview      *preview,
-                                                guchar          *src,
-                                                guchar          *dest,
-                                                gint             x,
-                                                gint             y,
-                                                gint             w);
-/* No idea */
+  /* Create the toplevel window */
 
-void            gtk_preview_draw_row           (GtkPreview      *preview,
-                                                guchar          *data,
-                                                gint             x,
-                                                gint             y,
-                                                gint             w);
-/* Described in the text */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
 
-void            gtk_preview_set_expand         (GtkPreview      *preview,
-                                                gint             expand);
-/* No idea */
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+  /* Create a toggle button to act as the selection */
 
-/* No clue for any of the below but    */
-/* should be standard for most widgets */
-void            gtk_preview_set_gamma          (double           gamma);
-void            gtk_preview_set_color_cube     (guint            nred_shades,
-                                                guint            ngreen_shades,
-                                                guint            nblue_shades,
-                                                guint            ngray_shades);
-void            gtk_preview_set_install_cmap   (gint             install_cmap);
-void            gtk_preview_set_reserved       (gint             nreserved);
-GdkVisual*      gtk_preview_get_visual         (void);
-GdkColormap*    gtk_preview_get_cmap           (void);
-GtkPreviewInfo* gtk_preview_get_info           (void);
+  selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
+  gtk_container_add (GTK_CONTAINER (window), selection_button);
+  gtk_widget_show (selection_button);
 
-That's all, folks!
+  gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
+                     GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
+  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
+                     GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
+
+  gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
+                            GDK_SELECTION_TYPE_STRING,
+                            selection_handle, NULL);
 
+  gtk_widget_show (selection_button);
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+/* example-end */
 </verb></tscreen>
 
+
 <!-- ***************************************************************** -->
-<sect>The EventBox Widget<label id="sec_The_EventBox_Widget">
+<sect>glib<label id="sec_glib">
 <!-- ***************************************************************** -->
-<p> 
-Some gtk widgets don't have associated X windows, so they just draw on 
-their parents. Because of this, they cannot recieve events
-and if they are incorrectly sized, they don't clip so you can get
-messy overwritting etc. If you require more from these widgets, the
-EventBox is for you.
-
-At first glance, the EventBox widget might appear to be totally
-useless. It draws nothing on the screen and responds to no
-events. However, it does serve a function - it provides an X window for
-its child widget. This is important as many GTK widgets do not
-have an associated X window. Not having an X window saves memory and
-improves performance, but also has some drawbacks. A widget without an
-X window cannot receive events, and does not perform any clipping on
-it's contents. Although the name <em/EventBox/ emphasizes the
-event-handling function, the widget can also be used for clipping. 
-(And more ... see the example below.)
+<p>
+glib provides many useful functions and definitions available for use
+when creating GDK and GTK applications. I will list them all here with
+a brief explanation. Many are duplicates of standard libc functions so
+I won't go into detail on those. This is mostly to be used as a reference,
+so you know what is available for use.
 
-To create a new EventBox widget, use:
+<!-- ----------------------------------------------------------------- -->
+<sect1>Definitions
+<p>
+Definitions for the extremes of many of the standard types are:
 
 <tscreen><verb>
-GtkWidget *gtk_event_box_new( void );
+G_MINFLOAT
+G_MAXFLOAT
+G_MINDOUBLE
+G_MAXDOUBLE
+G_MINSHORT
+G_MAXSHORT
+G_MININT
+G_MAXINT
+G_MINLONG
+G_MAXLONG
 </verb></tscreen>
 
-A child widget can then be added to this EventBox:
+Also, the following typedefs. The ones left unspecified are dynamically set
+depending on the architecture. Remember to avoid counting on the size of a
+pointer if you want to be portable! Eg, a pointer on an Alpha is 8 bytes, but 4
+on Intel.
 
 <tscreen><verb>
-gtk_container_add( GTK_CONTAINER(event_box), widget );
-</verb></tscreen>
+char   gchar;
+short  gshort;
+long   glong;
+int    gint;
+char   gboolean;
 
-The following example demonstrates both uses of an EventBox - a label
-is created that is clipped to a small box, and set up so that a
-mouse-click on the label causes the program to exit.
+unsigned char   guchar;
+unsigned short  gushort;
+unsigned long   gulong;
+unsigned int    guint;
 
-<tscreen><verb>
-/* example-start eventbox eventbox.c */
+float   gfloat;
+double  gdouble;
+long double gldouble;
 
-#include <gtk/gtk.h>
+void* gpointer;
 
-int 
-main (int argc, char *argv[])
-{
-    GtkWidget *window;
-    GtkWidget *event_box;
-    GtkWidget *label;
-    
-    gtk_init (&amp;argc, &amp;argv);
-    
-    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-    
-    gtk_window_set_title (GTK_WINDOW (window), "Event Box");
-    
-    gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
-    
-    gtk_container_border_width (GTK_CONTAINER (window), 10);
-    
-    /* Create an EventBox and add it to our toplevel window */
-    
-    event_box = gtk_event_box_new ();
-    gtk_container_add (GTK_CONTAINER(window), event_box);
-    gtk_widget_show (event_box);
-    
-    /* Create a long label */
-    
-    label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
-    gtk_container_add (GTK_CONTAINER (event_box), label);
-    gtk_widget_show (label);
-    
-    /* Clip it short. */
-    gtk_widget_set_usize (label, 110, 20);
-    
-    /* And bind an action to it */
-    gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
-    gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
-                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
-    
-    /* Yet one more thing you need an X window for ... */
-    
-    gtk_widget_realize (event_box);
-    gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
-    
-    gtk_widget_show (window);
-    
-    gtk_main ();
-    
-    return 0;
-}
-/* example-end */
+gint8
+guint8
+gint16
+guint16
+gint32
+guint32
 </verb></tscreen>
 
-<!-- ***************************************************************** -->
-<sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
-<!-- ***************************************************************** -->
+<!-- ----------------------------------------------------------------- -->
+<sect1>Doubly Linked Lists
 <p>
-This describes the functions used to operate on widgets.  These can be used
-to set style, padding, size etc.
-
-(Maybe I should make a whole section on accelerators.)
+The following functions are used to create, manage, and destroy doubly
+linked lists.  I assume you know what linked lists are, as it is beyond the scope
+of this document to explain them.  Of course, it's not required that you
+know these for general use of GTK, but they are nice to know.
 
 <tscreen><verb>
-void gtk_widget_install_accelerator( GtkWidget           *widget,
-                                     GtkAcceleratorTable *table,
-                                     gchar               *signal_name,
-                                     gchar                key,
-                                     guint8               modifiers );
+GList *g_list_alloc( void );
 
-void gtk_widget_remove_accelerator ( GtkWidget           *widget,
-                                     GtkAcceleratorTable *table,
-                                     gchar               *signal_name);
+void g_list_free( GList *list );
 
-void gtk_widget_activate( GtkWidget *widget );
+void g_list_free_1( GList *list );
 
-void gtk_widget_set_name( GtkWidget *widget,
-                          gchar     *name );
+GList *g_list_append( GList     *list,
+                      gpointer   data );
+                          
+GList *g_list_prepend( GList    *list,
+                       gpointer  data );
+                       
+GList *g_list_insert( GList    *list,
+                      gpointer  data,
+                           gint      position );
 
-gchar *gtk_widget_get_name( GtkWidget *widget );
+GList *g_list_remove( GList    *list,
+                      gpointer  data );
+                          
+GList *g_list_remove_link( GList *list,
+                           GList *link );
 
-void gtk_widget_set_sensitive( GtkWidget *widget,
-                               gint       sensitive );
+GList *g_list_reverse( GList *list );
+
+GList *g_list_nth( GList *list,
+                   gint   n );
+                          
+GList *g_list_find( GList    *list,
+                    gpointer  data );
+
+GList *g_list_last( GList *list );
+
+GList *g_list_first( GList *list );
+
+gint g_list_length( GList *list );
+
+void g_list_foreach( GList    *list,
+                     GFunc     func,
+                     gpointer  user_data );
+</verb></tscreen>                                            
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Singly Linked Lists
+<p>
+Many of the above functions for singly linked lists are identical to the
+above. Here is a complete list:
+<tscreen><verb>
+GSList *g_slist_alloc( void );
+
+void g_slist_free( GSList *list );
+
+void g_slist_free_1( GSList *list );
+
+GSList *g_slist_append( GSList   *list,
+                        gpointer  data );
+               
+GSList *g_slist_prepend( GSList   *list,
+                         gpointer  data );
+                            
+GSList *g_slist_insert( GSList   *list,
+                        gpointer  data,
+                           gint      position );
+                            
+GSList *g_slist_remove( GSList   *list,
+                        gpointer  data );
+                            
+GSList *g_slist_remove_link( GSList *list,
+                             GSList *link );
+                            
+GSList *g_slist_reverse( GSList *list );
+
+GSList *g_slist_nth( GSList *list,
+                     gint    n );
+                            
+GSList *g_slist_find( GSList   *list,
+                      gpointer  data );
+                            
+GSList *g_slist_last( GSList *list );
 
-void gtk_widget_set_style( GtkWidget *widget,
-                           GtkStyle  *style );
-                                          
-GtkStyle *gtk_widget_get_style( GtkWidget *widget );
+gint g_slist_length( GSList *list );
 
-GtkStyle *gtk_widget_get_default_style( void );
+void g_slist_foreach( GSList   *list,
+                      GFunc     func,
+                           gpointer  user_data );
+       
+</verb></tscreen>
 
-void gtk_widget_set_uposition( GtkWidget *widget,
-                               gint       x,
-                               gint       y );
+<!-- ----------------------------------------------------------------- -->
+<sect1>Memory Management
+<p>
+<tscreen><verb>
+gpointer g_malloc( gulong size );
+</verb></tscreen>
 
-void gtk_widget_set_usize( GtkWidget *widget,
-                           gint       width,
-                           gint       height );
+This is a replacement for malloc(). You do not need to check the return
+vaule as it is done for you in this function.
 
-void gtk_widget_grab_focus( GtkWidget *widget );
+<tscreen><verb>
+gpointer g_malloc0( gulong size );
+</verb></tscreen>
 
-void gtk_widget_show( GtkWidget *widget );
+Same as above, but zeroes the memory before returning a pointer to it.
 
-void gtk_widget_hide( GtkWidget *widget );
+<tscreen><verb>
+gpointer g_realloc( gpointer mem,
+                    gulong   size );
 </verb></tscreen>
 
-<!-- ***************************************************************** -->
-<sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
-<!-- ***************************************************************** -->
-
-<!-- ----------------------------------------------------------------- -->
-<sect1>Timeouts
-<p>
-You may be wondering how you make GTK do useful work when in gtk_main.
-Well, you have several options. Using the following functions you can
-create a timeout function that will be called every "interval"
-milliseconds.
+Relocates "size" bytes of memory starting at "mem".  Obviously, the
+memory should have been previously allocated.
 
 <tscreen><verb>
-gint gtk_timeout_add( guint32     interval,
-                      GtkFunction function,
-                      gpointer    data );
+void g_free( gpointer mem );
 </verb></tscreen>
 
-The first argument is the number of milliseconds between calls to your
-function.  The second argument is the function you wish to have called, and
-the third, the data passed to this callback function. The return value is
-an integer "tag" which may be used to stop the timeout by calling:
+Frees memory. Easy one.
 
 <tscreen><verb>
-void gtk_timeout_remove( gint tag );
+void g_mem_profile( void );
 </verb></tscreen>
 
-You may also stop the timeout function by returning zero or FALSE from
-your callback function. Obviously this means if you want your function to
-continue to be called, it should return a non-zero value, ie TRUE.
-
-The declaration of your callback should look something like this:
+Dumps a profile of used memory, but requries that you add #define
+MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
 
 <tscreen><verb>
-gint timeout_callback( gpointer data );
+void g_mem_check( gpointer mem );
 </verb></tscreen>
 
+Checks that a memory location is valid.  Requires you add #define
+MEM_CHECK to the top of gmem.c and re-make and make install.
+
 <!-- ----------------------------------------------------------------- -->
-<sect1>Monitoring IO
+<sect1>Timers
 <p>
-Another nifty feature of GTK, is the ability to have it check for data on a
-file descriptor for you (as returned by open(2) or socket(2)). This is
-especially useful for networking applications. The function:
+Timer functions..
 
 <tscreen><verb>
-gint gdk_input_add( gint              source,
-                    GdkInputCondition condition,
-                    GdkInputFunction  function,
-                    gpointer          data );
-</verb></tscreen>
-
-Where the first argument is the file descriptor you wish to have watched,
-and the second specifies what you want GDK to look for.  This may be one of:
+GTimer *g_timer_new( void );
 
-<itemize>
-<item>GDK_INPUT_READ - Call your function when there is data ready for
-reading on your file descriptor.
+void g_timer_destroy( GTimer *timer );
 
-<item>GDK_INPUT_WRITE - Call your function when the file descriptor is
-ready for writing.
-</itemize>
+void g_timer_start( GTimer  *timer );
 
-As I'm sure you've figured out already, the third argument is the function
-you wish to have called when the above conditions are satisfied, and the
-fourth is the data to pass to this function.
+void g_timer_stop( GTimer  *timer );
 
-The return value is a tag that may be used to stop GDK from monitoring this
-file descriptor using the following function.
+void g_timer_reset( GTimer  *timer );
 
-<tscreen><verb>
-void gdk_input_remove( gint tag );
-</verb></tscreen>
+gdouble g_timer_elapsed( GTimer *timer,
+                         gulong *microseconds );
+</verb></tscreen>                       
 
-The callback function should be declared as:
+<!-- ----------------------------------------------------------------- -->
+<sect1>String Handling
+<p>
+A whole mess of string handling functions. They all look very interesting, and
+probably better for many purposes than the standard C string functions, but
+require documentation.
 
 <tscreen><verb>
-void input_callback( gpointer          data,
-                     gint              source, 
-                     GdkInputCondition condition );
-</verb></tscreen>
+GString *g_string_new( gchar *init );
 
-Where <tt/source/ and <tt/condition/ are as specified above.
+void g_string_free( GString *string,
+                    gint     free_segment );
+                            
+GString *g_string_assign( GString *lval,
+                          gchar   *rval );
+                            
+GString *g_string_truncate( GString *string,
+                            gint     len );
+                            
+GString *g_string_append( GString *string,
+                          gchar   *val );
+                           
+GString *g_string_append_c( GString *string,
+                            gchar    c );
+       
+GString *g_string_prepend( GString *string,
+                           gchar   *val );
+                            
+GString *g_string_prepend_c( GString *string,
+                             gchar    c );
+       
+void g_string_sprintf( GString *string,
+                       gchar   *fmt,
+                       ...);
+       
+void g_string_sprintfa ( GString *string,
+                         gchar   *fmt,
+                         ... );
+</verb></tscreen>                                                        
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Idle Functions
+<sect1>Utility and Error Functions
 <p>
-<!-- Need to check on idle priorities - TRG -->
-What if you have a function you want called when nothing else is
-happening ?
-
 <tscreen><verb>
-gint gtk_idle_add( GtkFunction function,
-                   gpointer    data );
+gchar *g_strdup( const gchar *str );
 </verb></tscreen>
 
-This causes GTK to call the specified function whenever nothing else is
-happening.
+Replacement strdup function.  Copies the original strings contents to
+newly allocated memory, and returns a pointer to it.
 
 <tscreen><verb>
-void gtk_idle_remove( gint tag );
+gchar *g_strerror( gint errnum );
 </verb></tscreen>
 
-I won't explain the meaning of the arguments as they follow very much like
-the ones above. The function pointed to by the first argument to
-gtk_idle_add will be called whenever the opportunity arises. As with the
-others, returning FALSE will stop the idle function from being called.
+I recommend using this for all error messages.  It's much nicer, and more
+portable than perror() or others.  The output is usually of the form:
 
-<!-- ***************************************************************** -->
-<sect>Managing Selections
-<!-- ***************************************************************** -->
+<tscreen><verb>
+program name:function that failed:file or further description:strerror
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Overview
-<p>
-One type of interprocess communication supported by GTK is
-<em>selections</em>. A selection identifies a chunk of data, for
-instance, a portion of text, selected by the user in some fashion, for
-instance, by dragging with the mouse. Only one application on a
-display, (the <em>owner</em> can own a particular selection at one
-time, so when a selection is claimed by one application, the previous
-owner must indicate to the user that selection has been
-relinquished. Other applications can request the contents of a
-selection in different forms, called <em>targets</em>. There can be
-any number of selections, but most X applications only handle one, the
-<em>primary selection</em>.
+Here's an example of one such call used in our hello_world program:
 
-In most cases, it isn't necessary for a GTK application to deal with
-selections itself. The standard widgets, such as the Entry widget,
-already have the capability to claim the selection when appropriate
-(e.g., when the user drags over text), and to retrieve the contents of
-the selection owned by another widget, or another application (e.g.,
-when the user clicks the second mouse button). However, there may be
-cases in which you want to give other widgets the ability to supply
-the selection, or you wish to retrieve targets not supported by
-default.
+<tscreen><verb>
+g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
+</verb></tscreen>
 
-A fundamental concept needed to understand selection handling is that
-of the <em>atom</em>. An atom is an integer that uniquely identifies a
-string (on a certain display). Certain atoms are predefined by the X
-server, and in some cases there are constants in <tt>gtk.h</tt>
-corresponding to these atoms. For instance the constant
-<tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
-In other cases, you should use the functions
-<tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
-and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
-selections and targets are identifed by atoms.
+<tscreen><verb>
+void g_error( gchar *format, ... );
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Retrieving the selection
-<p>
-Retrieving the selection is an asynchronous process. To start the
-process, you call:
+Prints an error message. The format is just like printf, but it
+prepends "** ERROR **: " to your message, and exits the program.  
+Use only for fatal errors.
 
 <tscreen><verb>
-gint gtk_selection_convert( GtkWidget *widget, 
-                            GdkAtom    selection, 
-                            GdkAtom    target,
-                            guint32    time );
-</verb</tscreen>
-
-This <em>converts</em> the selection into the form specified by
-<tt/target/. If at all possible, the time field should be the time
-from the event that triggered the selection. This helps make sure that
-events occur in the order that the user requested them. However, if it
-is not available (for instance, if the conversion was triggered by
-a "clicked" signal), then you can use the constant
-<tt>GDK_CURRENT_TIME</tt>.
+void g_warning( gchar *format, ... );
+</verb></tscreen>
 
-When the selection owner responds to the request, a
-"selection_received" signal is sent to your application. The handler
-for this signal receives a pointer to a <tt>GtkSelectionData</tt>
-structure, which is defined as:
+Same as above, but prepends "** WARNING **: ", and does not exit the
+program.
 
 <tscreen><verb>
-struct _GtkSelectionData
-{
-  GdkAtom selection;
-  GdkAtom target;
-  GdkAtom type;
-  gint    format;
-  guchar *data;
-  gint    length;
-};
+void g_message( gchar *format, ... );
+</verb></tscreen>
+
+Prints "message: " prepended to the string you pass in.
+
+<tscreen><verb>
+void g_print( gchar *format, ... );
 </verb></tscreen>
 
-<tt>selection</tt> and <tt>target</tt> are the values you gave in your
-<tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
-identifies the type of data returned by the selection owner. Some
-possible values are "STRING", a string of latin-1 characters, "ATOM",
-a series of atoms, "INTEGER", an integer, etc. Most targets can only
-return one type. <tt/format/ gives the length of the units (for
-instance characters) in bits. Usually, you don't care about this when
-receiving data. <tt>data</tt> is a pointer to the returned data, and
-<tt>length</tt> gives the length of the returned data, in bytes. If
-<tt>length</tt> is negative, then an error occurred and the selection
-could not be retrieved. This might happen if no application owned the
-selection, or if you requested a target that the application didn't
-support. The buffer is actually guaranteed to be one byte longer than
-<tt>length</tt>; the extra byte will always be zero, so it isn't
-necessary to make a copy of strings just to null terminate them.
+Replacement for printf().
 
-In the following example, we retrieve the special target "TARGETS",
-which is a list of all targets into which the selection can be
-converted.
+And our last function:
 
 <tscreen><verb>
-/* example-start selection gettargets.c */
-
-#include <gtk/gtk.h>
+gchar *g_strsignal( gint signum );
+</verb></tscreen>
 
-void selection_received (GtkWidget *widget, 
-                        GtkSelectionData *selection_data, 
-                        gpointer data);
+Prints out the name of the Unix system signal given the signal number.
+Useful in generic signal handling functions.
 
-/* Signal handler invoked when user clicks on the "Get Targets" button */
-void
-get_targets (GtkWidget *widget, gpointer data)
-{
-  static GdkAtom targets_atom = GDK_NONE;
+All of the above are more or less just stolen from glib.h.  If anyone cares
+to document any function, just send me an email!
 
-  /* Get the atom corresonding to the string "TARGETS" */
-  if (targets_atom == GDK_NONE)
-    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
+<!-- ***************************************************************** -->
+<sect>GTK's rc Files
+<!-- ***************************************************************** -->
+<p>
+GTK has it's own way of dealing with application defaults, by using rc
+files. These can be used to set the colors of just about any widget, and
+can also be used to tile pixmaps onto the background of some widgets.  
 
-  /* And request the "TARGETS" target for the primary selection */
-  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
-                        GDK_CURRENT_TIME);
-}
+<!-- ----------------------------------------------------------------- -->
+<sect1>Functions For rc Files 
+<p>
+When your application starts, you should include a call to:
 
-/* Signal handler called when the selections owner returns the data */
-void
-selection_received (GtkWidget *widget, GtkSelectionData *selection_data, 
-                   gpointer data)
-{
-  GdkAtom *atoms;
-  GList *item_list;
-  int i;
+<tscreen><verb>
+void gtk_rc_parse( char *filename );
+</verb></tscreen>
 
-  /* **** IMPORTANT **** Check to see if retrieval succeeded  */
-  if (selection_data->length < 0)
-    {
-      g_print ("Selection retrieval failed\n");
-      return;
-    }
-  /* Make sure we got the data in the expected form */
-  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
-    {
-      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
-      return;
-    }
-  
-  /* Print out the atoms we received */
-  atoms = (GdkAtom *)selection_data->data;
+Passing in the filename of your rc file.  This will cause GTK to parse this
+file, and use the style settings for the widget types defined there.
 
-  item_list = NULL;
-  for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
-    {
-      char *name;
-      name = gdk_atom_name (atoms[i]);
-      if (name != NULL)
-       g_print ("%s\n",name);
-      else
-       g_print ("(bad atom)\n");
-    }
+If you wish to have a special set of widgets that can take on a different
+style from others, or any other logical division of widgets, use a call to:
 
-  return;
-}
+<tscreen><verb>
+void gtk_widget_set_name( GtkWidget *widget,
+                          gchar     *name );
+</verb></tscreen>
 
-int 
-main (int argc, char *argv[])
-{
-  GtkWidget *window;
-  GtkWidget *button;
-  
-  gtk_init (&amp;argc, &amp;argv);
+Passing your newly created widget as the first argument, and the name
+you wish to give it as the second. This will allow you to change the
+attributes of this widget by name through the rc file.
 
-  /* Create the toplevel window */
+If we use a call something like this:
 
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
-  gtk_container_border_width (GTK_CONTAINER (window), 10);
+<tscreen><verb>
+button = gtk_button_new_with_label ("Special Button");
+gtk_widget_set_name (button, "special button");
+</verb></tscreen>
 
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+Then this button is given the name "special button" and may be addressed by
+name in the rc file as "special button.GtkButton".  [<--- Verify ME!]
 
-  /* Create a button the user can click to get targets */
+The example rc file below, sets the properties of the main window, and lets
+all children of that main window inherit the style described by the "main
+button" style.  The code used in the application is:
 
-  button = gtk_button_new_with_label ("Get Targets");
-  gtk_container_add (GTK_CONTAINER (window), button);
+<tscreen><verb>
+window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+gtk_widget_set_name (window, "main window");
+</verb></tscreen>
 
-  gtk_signal_connect (GTK_OBJECT(button), "clicked",
-                     GTK_SIGNAL_FUNC (get_targets), NULL);
-  gtk_signal_connect (GTK_OBJECT(button), "selection_received",
-                     GTK_SIGNAL_FUNC (selection_received), NULL);
+And then the style is defined in the rc file using:
 
-  gtk_widget_show (button);
-  gtk_widget_show (window);
-  
-  gtk_main ();
-  
-  return 0;
-}
-/* example-end */
+<tscreen><verb>
+widget "main window.*GtkButton*" style "main_button"
 </verb></tscreen>
 
+Which sets all the GtkButton widgets in the "main window" to the
+"main_buttons" style as defined in the rc file.
+
+As you can see, this is a fairly powerful and flexible system.  Use your
+imagination as to how best to take advantage of this.
+
 <!-- ----------------------------------------------------------------- -->
-<sect1> Supplying the selection 
+<sect1>GTK's rc File Format
 <p>
-Supplying the selection is a bit more complicated. You must register 
-handlers that will be called when your selection is requested. For
-each selection/target pair you will handle, you make a call to:
+The format of the GTK file is illustrated in the example below. This is
+the testgtkrc file from the GTK distribution, but I've added a
+few comments and things. You may wish to include this explanation
+your application to allow the user to fine tune his application.
 
-<tscreen><verb>
-void gtk_selection_add_handler( GtkWidget            *widget, 
-                                GdkAtom               selection,
-                                GdkAtom               target,
-                                GtkSelectionFunction  function,
-                                GtkRemoveFunction     remove_func,
-                                gpointer              data );
-</verb></tscreen>
+There are several directives to change the attributes of a widget.
 
-<tt/widget/, <tt/selection/, and <tt/target/ identify the requests
-this handler will manage.  <tt/remove_func/, if not
-NULL, will be called when the signal handler is removed. This is
-useful, for instance, for interpreted languages which need to
-keep track of a reference count for <tt/data/.
+<itemize>
+<item>fg - Sets the foreground color of a widget.
+<item>bg - Sets the background color of a widget.
+<item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
+<item>font - Sets the font to be used with the given widget.
+</itemize>
 
-The callback function has the signature:
+In addition to this, there are several states a widget can be in, and you
+can set different colors, pixmaps and fonts for each state. These states are:
 
-<tscreen><verb>
-typedef void (*GtkSelectionFunction)( GtkWidget        *widget, 
-                                      GtkSelectionData *selection_data,
-                                      gpointer          data );
+<itemize>
+<item>NORMAL - The normal state of a widget, without the mouse over top of
+it, and not being pressed etc.
+<item>PRELIGHT - When the mouse is over top of the widget, colors defined
+using this state will be in effect.
+<item>ACTIVE - When the widget is pressed or clicked it will be active, and
+the attributes assigned by this tag will be in effect.
+<item>INSENSITIVE - When a widget is set insensitive, and cannot be
+activated, it will take these attributes.
+<item>SELECTED - When an object is selected, it takes these attributes.
+</itemize>
+
+When using the "fg" and "bg" keywords to set the colors of widgets, the
+format is:
 
+<tscreen><verb>
+fg[<STATE>] = { Red, Green, Blue }
 </verb></tscreen>
 
-The GtkSelectionData is the same as above, but this time, we're
-responsible for filling in the fields <tt/type/, <tt/format/,
-<tt/data/, and <tt/length/. (The <tt/format/ field is actually
-important here - the X server uses it to figure out whether the data
-needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
-character - or 32 - <em/i.e./ a. integer.) This is done by calling the
-function:
+Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
+Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
+white. They must be in float form, or they will register as 0, so a straight 
+"1" will not work, it must be "1.0".  A straight "0" is fine because it 
+doesn't matter if it's not recognized.  Unrecognized values are set to 0.
 
+bg_pixmap is very similar to the above, except the colors are replaced by a
+filename.
+
+pixmap_path is a list of paths seperated by ":"'s.  These paths will be
+searched for any pixmap you specify.
+
+The font directive is simply:
 <tscreen><verb>
-void gtk_selection_data_set( GtkSelectionData *selection_data,
-                             GdkAtom           type,
-                             gint              format,
-                             guchar           *data,
-                             gint              length );
+font = "<font name>"
 </verb></tscreen>
 
-This function takes care of properly making a copy of the data so that
-you don't have to worry about keeping it around. (You should not fill
-in the fields of the GtkSelectionData structure by hand.)
+Where the only hard part is figuring out the font string. Using xfontsel or
+similar utility should help.
+
+The "widget_class" sets the style of a class of widgets. These classes are
+listed in the widget overview on the class hierarchy.
+
+The "widget" directive sets a specificaly named set of widgets to a
+given style, overriding any style set for the given widget class.
+These widgets are registered inside the application using the
+gtk_widget_set_name() call. This allows you to specify the attributes of a
+widget on a per widget basis, rather than setting the attributes of an
+entire widget class. I urge you to document any of these special widgets so
+users may customize them.
+
+When the keyword <tt>parent</> is used as an attribute, the widget will take on
+the attributes of it's parent in the application.
 
-When prompted by the user, you claim ownership of the selection by
-calling:
+When defining a style, you may assign the attributes of a previously defined
+style to this new one.
 
 <tscreen><verb>
-gint gtk_selection_owner_set( GtkWidget *widget,
-                              GdkAtom    selection,
-                              guint32    time );
+style "main_button" = "button"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+  bg[PRELIGHT] = { 0.75, 0, 0 }
+}
 </verb></tscreen>
 
-If another application claims ownership of the selection, you will
-receive a "selection_clear_event".
+This example takes the "button" style, and creates a new "main_button" style
+simply by changing the font and prelight background color of the "button"
+style.
 
-As an example of supplying the selection, the following program adds
-selection functionality to a toggle button. When the toggle button is
-depressed, the program claims the primary selection. The only target
-supported (aside from certain targets like "TARGETS" supplied by GTK
-itself), is the "STRING" target. When this target is requested, a
-string representation of the time is returned.
+Of course, many of these attributes don't apply to all widgets. It's a
+simple matter of common sense really. Anything that could apply, should.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Example rc file
+<p>
 
 <tscreen><verb>
-/* example-start selection setselection.c */
+# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
+#
+pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
+#
+# style <name> [= <name>]
+# {
+#   <option>
+# }
+#
+# widget <widget_set> style <style_name>
+# widget_class <widget_class_set> style <style_name>
 
-#include <gtk/gtk.h>
-#include <time.h>
 
-/* Callback when the user toggles the selection */
-void
-selection_toggled (GtkWidget *widget, gint *have_selection)
+# Here is a list of all the possible states.  Note that some do not apply to
+# certain widgets.
+#
+# NORMAL - The normal state of a widget, without the mouse over top of
+# it, and not being pressed etc.
+#
+# PRELIGHT - When the mouse is over top of the widget, colors defined
+# using this state will be in effect.
+#
+# ACTIVE - When the widget is pressed or clicked it will be active, and
+# the attributes assigned by this tag will be in effect.
+#
+# INSENSITIVE - When a widget is set insensitive, and cannot be
+# activated, it will take these attributes.
+#
+# SELECTED - When an object is selected, it takes these attributes.
+#
+# Given these states, we can set the attributes of the widgets in each of
+# these states using the following directives.
+#
+# fg - Sets the foreground color of a widget.
+# fg - Sets the background color of a widget.
+# bg_pixmap - Sets the background of a widget to a tiled pixmap.
+# font - Sets the font to be used with the given widget.
+#
+
+# This sets a style called "button".  The name is not really important, as
+# it is assigned to the actual widgets at the bottom of the file.
+
+style "window"
 {
-  if (GTK_TOGGLE_BUTTON(widget)->active)
-    {
-      *have_selection = gtk_selection_owner_set (widget,
-                                                GDK_SELECTION_PRIMARY,
-                                                GDK_CURRENT_TIME);
-      /* if claiming the selection failed, we return the button to
-        the out state */
-      if (!*have_selection)
-       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
-    }
-  else
-    {
-      if (*have_selection)
-       {
-         /* Before clearing the selection by setting the owner to NULL,
-            we check if we are the actual owner */
-         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
-           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
-                                    GDK_CURRENT_TIME);
-         *have_selection = FALSE;
-       }
-    }
+  #This sets the padding around the window to the pixmap specified.
+  #bg_pixmap[<STATE>] = "<pixmap filename>"
+  bg_pixmap[NORMAL] = "warning.xpm"
 }
 
-/* Called when another application claims the selection */
-gint
-selection_clear (GtkWidget *widget, GdkEventSelection *event,
-                gint *have_selection)
+style "scale"
 {
-  *have_selection = FALSE;
-  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
-
-  return TRUE;
+  #Sets the foreground color (font color) to red when in the "NORMAL"
+  #state.
+  
+  fg[NORMAL] = { 1.0, 0, 0 }
+  
+  #Sets the background pixmap of this widget to that of it's parent.
+  bg_pixmap[NORMAL] = "<parent>"
 }
 
-/* Supplies the current time as the selection. */
-void
-selection_handle (GtkWidget *widget, 
-                 GtkSelectionData *selection_data,
-                 gpointer data)
+style "button"
 {
-  gchar *timestr;
-  time_t current_time;
+  # This shows all the possible states for a button.  The only one that
+  # doesn't apply is the SELECTED state.
+  
+  fg[PRELIGHT] = { 0, 1.0, 1.0 }
+  bg[PRELIGHT] = { 0, 0, 1.0 }
+  bg[ACTIVE] = { 1.0, 0, 0 }
+  fg[ACTIVE] = { 0, 1.0, 0 }
+  bg[NORMAL] = { 1.0, 1.0, 0 }
+  fg[NORMAL] = { .99, 0, .99 }
+  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
+  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
+}
 
-  current_time = time (NULL);
-  timestr = asctime (localtime(&amp;current_time)); 
-  /* When we return a single string, it should not be null terminated.
-     That will be done for us */
+# In this example, we inherit the attributes of the "button" style and then
+# override the font and background color when prelit to create a new
+# "main_button" style.
 
-  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
-                         8, timestr, strlen(timestr));
+style "main_button" = "button"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+  bg[PRELIGHT] = { 0.75, 0, 0 }
 }
 
-int
-main (int argc, char *argv[])
+style "toggle_button" = "button"
 {
-  GtkWidget *window;
-
-  GtkWidget *selection_button;
-
-  static int have_selection = FALSE;
+  fg[NORMAL] = { 1.0, 0, 0 }
+  fg[ACTIVE] = { 1.0, 0, 0 }
   
-  gtk_init (&amp;argc, &amp;argv);
-
-  /* Create the toplevel window */
-
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
-  gtk_container_border_width (GTK_CONTAINER (window), 10);
+  # This sets the background pixmap of the toggle_button to that of it's
+  # parent widget (as defined in the application).
+  bg_pixmap[NORMAL] = "<parent>"
+}
 
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+style "text"
+{
+  bg_pixmap[NORMAL] = "marble.xpm"
+  fg[NORMAL] = { 1.0, 1.0, 1.0 }
+}
 
-  /* Create a toggle button to act as the selection */
+style "ruler"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+}
 
-  selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
-  gtk_container_add (GTK_CONTAINER (window), selection_button);
-  gtk_widget_show (selection_button);
+# pixmap_path "~/.pixmaps"
 
-  gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
-                     GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
-  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
-                     GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
+# These set the widget types to use the styles defined above.
+# The widget types are listed in the class hierarchy, but could probably be
+# just listed in this document for the users reference.
 
-  gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
-                            GDK_SELECTION_TYPE_STRING,
-                            selection_handle, NULL);
+widget_class "GtkWindow" style "window"
+widget_class "GtkDialog" style "window"
+widget_class "GtkFileSelection" style "window"
+widget_class "*Gtk*Scale" style "scale"
+widget_class "*GtkCheckButton*" style "toggle_button"
+widget_class "*GtkRadioButton*" style "toggle_button"
+widget_class "*GtkButton*" style "button"
+widget_class "*Ruler" style "ruler"
+widget_class "*GtkText" style "text"
 
-  gtk_widget_show (selection_button);
-  gtk_widget_show (window);
-  
-  gtk_main ();
-  
-  return 0;
-}
-/* example-end */
+# This sets all the buttons that are children of the "main window" to
+# the main_buton style.  These must be documented to be taken advantage of.
+widget "main window.*GtkButton*" style "main_button"
 </verb></tscreen>
 
-
 <!-- ***************************************************************** -->
-<sect>glib<label id="sec_glib">
+<sect>Writing Your Own Widgets 
 <!-- ***************************************************************** -->
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Overview
 <p>
-glib provides many useful functions and definitions available for use
-when creating GDK and GTK applications. I will list them all here with
-a brief explanation. Many are duplicates of standard libc functions so
-I won't go into detail on those. This is mostly to be used as a reference,
-so you know what is available for use.
+Although the GTK distribution comes with many types of widgets that
+should cover most basic needs, there may come a time when you need to
+create your own new widget type. Since GTK uses widget inheretence
+extensively, and there is already a widget that is close to what you want,
+it is often possible to make a useful new widget type in
+just a few lines of code. But before starting work on a new widget, check
+around first to make sure that someone has not already written
+it. This will prevent duplication of effort and keep the number of
+GTK widgets out there to a minimum, which will help keep both the code
+and the interface of different applications consistent. As a flip side
+to this, once you finish your widget, announce it to the world so
+other people can benefit. The best place to do this is probably the
+<tt>gtk-list</tt>.
+
+Complete sources for the example widgets are available at the place you 
+got this tutorial, or from:
+
+<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
+name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Definitions
+<sect1> The Anatomy Of A Widget
 <p>
-Definitions for the extremes of many of the standard types are:
+In order to create a new widget, it is important to have an
+understanding of how GTK objects work. This section is just meant as a
+brief overview. See the reference documentation for the details. 
+
+GTK widgets are implemented in an object oriented fashion. However,
+they are implemented in standard C. This greatly improves portability
+and stability over using current generation C++ compilers; however,
+it does mean that the widget writer has to pay attention to some of
+the implementation details. The information common to all instances of
+one class of widgets (e.g., to all Button widgets) is stored in the 
+<em>class structure</em>. There is only one copy of this in
+which is stored information about the class's signals
+(which act like virtual functions in C). To support inheritance, the
+first field in the class structure must be a copy of the parent's
+class structure. The declaration of the class structure of GtkButtton
+looks like:
 
 <tscreen><verb>
-G_MINFLOAT
-G_MAXFLOAT
-G_MINDOUBLE
-G_MAXDOUBLE
-G_MINSHORT
-G_MAXSHORT
-G_MININT
-G_MAXINT
-G_MINLONG
-G_MAXLONG
+struct _GtkButtonClass
+{
+  GtkContainerClass parent_class;
+
+  void (* pressed)  (GtkButton *button);
+  void (* released) (GtkButton *button);
+  void (* clicked)  (GtkButton *button);
+  void (* enter)    (GtkButton *button);
+  void (* leave)    (GtkButton *button);
+};
 </verb></tscreen>
 
-Also, the following typedefs. The ones left unspecified are dynamically set
-depending on the architecture. Remember to avoid counting on the size of a
-pointer if you want to be portable! Eg, a pointer on an Alpha is 8 bytes, but 4
-on Intel.
+When a button is treated as a container (for instance, when it is
+resized), its class structure can be cast to GtkContainerClass, and
+the relevant fields used to handle the signals.
+
+There is also a structure for each widget that is created on a
+per-instance basis. This structure has fields to store information that
+is different for each instance of the widget. We'll call this
+structure the <em>object structure</em>. For the Button class, it looks
+like:
 
 <tscreen><verb>
-char   gchar;
-short  gshort;
-long   glong;
-int    gint;
-char   gboolean;
+struct _GtkButton
+{
+  GtkContainer container;
 
-unsigned char   guchar;
-unsigned short  gushort;
-unsigned long   gulong;
-unsigned int    guint;
+  GtkWidget *child;
 
-float   gfloat;
-double  gdouble;
-long double gldouble;
+  guint in_button : 1;
+  guint button_down : 1;
+};
+</verb></tscreen>
 
-void* gpointer;
+Note that, similar to the class structure, the first field is the
+object structure of the parent class, so that this structure can be
+cast to the parent class's object structure as needed.
 
-gint8
-guint8
-gint16
-guint16
-gint32
-guint32
-</verb></tscreen>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Creating a Composite widget
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Doubly Linked Lists
+<sect2> Introduction
 <p>
-The following functions are used to create, manage, and destroy doubly
-linked lists.  I assume you know what linked lists are, as it is beyond the scope
-of this document to explain them.  Of course, it's not required that you
-know these for general use of GTK, but they are nice to know.
-
-<tscreen><verb>
-GList *g_list_alloc( void );
+One type of widget that you may be interested in creating is a
+widget that is merely an aggregate of other GTK widgets. This type of
+widget does nothing that couldn't be done without creating new
+widgets, but provides a convenient way of packaging user interface
+elements for reuse. The FileSelection and ColorSelection widgets in
+the standard distribution are examples of this type of widget.
 
-void g_list_free( GList *list );
+The example widget that we'll create in this section is the Tictactoe
+widget, a 3x3 array of toggle buttons which triggers a signal when all
+three buttons in a row, column, or on one of the diagonals are
+depressed. 
 
-void g_list_free_1( GList *list );
+<!-- ----------------------------------------------------------------- -->
+<sect2> Choosing a parent class
+<p>
+The parent class for a composite widget is typically the container
+class that holds all of the elements of the composite widget. For
+example, the parent class of the FileSelection widget is the
+Dialog class. Since our buttons will be arranged in a table, it
+might seem natural to make our parent class the GtkTable
+class. Unfortunately, this turns out not to work. The creation of a
+widget is divided among two functions - a <tt/WIDGETNAME_new()/
+function that the user calls, and a <tt/WIDGETNAME_init()/ function
+which does the basic work of initializing the widget which is
+independent of the arguments passed to the <tt/_new()/
+function. Descendent widgets only call the <tt/_init/ function of
+their parent widget. But this division of labor doesn't work well for
+tables, which when created, need to know the number of rows and
+columns in the table. Unless we want to duplicate most of the
+functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
+best avoid deriving it from GtkTable. For that reason, we derive it
+from GtkVBox instead, and stick our table inside the VBox.
 
-GList *g_list_append( GList     *list,
-                      gpointer   data );
-                          
-GList *g_list_prepend( GList    *list,
-                       gpointer  data );
-                       
-GList *g_list_insert( GList    *list,
-                      gpointer  data,
-                           gint      position );
+<!-- ----------------------------------------------------------------- -->
+<sect2> The header file
+<p>
+Each widget class has a header file which declares the object and
+class structures for that widget, along with public functions. 
+A couple of features are worth pointing out. To prevent duplicate
+definitions, we wrap the entire header file in:
 
-GList *g_list_remove( GList    *list,
-                      gpointer  data );
-                          
-GList *g_list_remove_link( GList *list,
-                           GList *link );
+<tscreen><verb>
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
+.
+.
+.
+#endif /* __TICTACTOE_H__ */
+</verb></tscreen>
 
-GList *g_list_reverse( GList *list );
+And to keep C++ programs that include the header file happy, in:
 
-GList *g_list_nth( GList *list,
-                   gint   n );
-                          
-GList *g_list_find( GList    *list,
-                    gpointer  data );
+<tscreen><verb>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+.
+.
+.
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+</verb></tscreen>
 
-GList *g_list_last( GList *list );
+Along with the functions and structures, we declare three standard
+macros in our header file, <tt/TICTACTOE(obj)/,
+<tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
+pointer into a pointer to the object or class structure, and check
+if an object is a Tictactoe widget respectively.
 
-GList *g_list_first( GList *list );
+Here is the complete header file:
 
-gint g_list_length( GList *list );
+<tscreen><verb>
+/* tictactoe.h */
 
-void g_list_foreach( GList    *list,
-                     GFunc     func,
-                     gpointer  user_data );
-</verb></tscreen>                                            
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Singly Linked Lists
-<p>
-Many of the above functions for singly linked lists are identical to the
-above. Here is a complete list:
-<tscreen><verb>
-GSList *g_slist_alloc( void );
+#include <gdk/gdk.h>
+#include <gtk/gtkvbox.h>
 
-void g_slist_free( GSList *list );
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
-void g_slist_free_1( GSList *list );
+#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
+#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
+#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
 
-GSList *g_slist_append( GSList   *list,
-                        gpointer  data );
-               
-GSList *g_slist_prepend( GSList   *list,
-                         gpointer  data );
-                            
-GSList *g_slist_insert( GSList   *list,
-                        gpointer  data,
-                           gint      position );
-                            
-GSList *g_slist_remove( GSList   *list,
-                        gpointer  data );
-                            
-GSList *g_slist_remove_link( GSList *list,
-                             GSList *link );
-                            
-GSList *g_slist_reverse( GSList *list );
 
-GSList *g_slist_nth( GSList *list,
-                     gint    n );
-                            
-GSList *g_slist_find( GSList   *list,
-                      gpointer  data );
-                            
-GSList *g_slist_last( GSList *list );
+typedef struct _Tictactoe       Tictactoe;
+typedef struct _TictactoeClass  TictactoeClass;
 
-gint g_slist_length( GSList *list );
+struct _Tictactoe
+{
+  GtkVBox vbox;
+  
+  GtkWidget *buttons[3][3];
+};
 
-void g_slist_foreach( GSList   *list,
-                      GFunc     func,
-                           gpointer  user_data );
-       
-</verb></tscreen>
+struct _TictactoeClass
+{
+  GtkVBoxClass parent_class;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Memory Management
-<p>
-<tscreen><verb>
-gpointer g_malloc( gulong size );
-</verb></tscreen>
+  void (* tictactoe) (Tictactoe *ttt);
+};
 
-This is a replacement for malloc(). You do not need to check the return
-vaule as it is done for you in this function.
+guint          tictactoe_get_type        (void);
+GtkWidget*     tictactoe_new             (void);
+void          tictactoe_clear           (Tictactoe *ttt);
 
-<tscreen><verb>
-gpointer g_malloc0( gulong size );
-</verb></tscreen>
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-Same as above, but zeroes the memory before returning a pointer to it.
+#endif /* __TICTACTOE_H__ */
 
-<tscreen><verb>
-gpointer g_realloc( gpointer mem,
-                    gulong   size );
 </verb></tscreen>
 
-Relocates "size" bytes of memory starting at "mem".  Obviously, the
-memory should have been previously allocated.
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <tt/_get_type()/ function.
+<p>
+We now continue on to the implementation of our widget. A core
+function for every widget is the function
+<tt/WIDGETNAME_get_type()/. This function, when first called, tells
+GTK about the widget class, and gets an ID that uniquely identifies
+the widget class. Upon subsequent calls, it just returns the ID.
 
 <tscreen><verb>
-void g_free( gpointer mem );
-</verb></tscreen>
+guint
+tictactoe_get_type ()
+{
+  static guint ttt_type = 0;
 
-Frees memory. Easy one.
+  if (!ttt_type)
+    {
+      GtkTypeInfo ttt_info =
+      {
+       "Tictactoe",
+       sizeof (Tictactoe),
+       sizeof (TictactoeClass),
+       (GtkClassInitFunc) tictactoe_class_init,
+       (GtkObjectInitFunc) tictactoe_init,
+       (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL
+      };
 
-<tscreen><verb>
-void g_mem_profile( void );
+      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
+    }
+
+  return ttt_type;
+}
 </verb></tscreen>
 
-Dumps a profile of used memory, but requries that you add #define
-MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
+The GtkTypeInfo structure has the following definition:
 
 <tscreen><verb>
-void g_mem_check( gpointer mem );
+struct _GtkTypeInfo
+{
+  gchar *type_name;
+  guint object_size;
+  guint class_size;
+  GtkClassInitFunc class_init_func;
+  GtkObjectInitFunc object_init_func;
+  GtkArgSetFunc arg_set_func;
+  GtkArgGetFunc arg_get_func;
+};
 </verb></tscreen>
 
-Checks that a memory location is valid.  Requires you add #define
-MEM_CHECK to the top of gmem.c and re-make and make install.
+The fields of this structure are pretty self-explanatory. We'll ignore
+the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important, 
+but as yet largely
+unimplemented, role in allowing widget options to be conveniently set
+from interpreted languages. Once GTK has a correctly filled in copy of
+this structure, it knows how to create objects of a particular widget
+type. 
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Timers
+<sect2> The <tt/_class_init()/ function
 <p>
-Timer functions..
+The <tt/WIDGETNAME_class_init()/ function initializes the fields of
+the widget's class structure, and sets up any signals for the
+class. For our Tictactoe widget it looks like:
 
 <tscreen><verb>
-GTimer *g_timer_new( void );
 
-void g_timer_destroy( GTimer *timer );
+enum {
+  TICTACTOE_SIGNAL,
+  LAST_SIGNAL
+};
 
-void g_timer_start( GTimer  *timer );
+static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
 
-void g_timer_stop( GTimer  *timer );
+static void
+tictactoe_class_init (TictactoeClass *class)
+{
+  GtkObjectClass *object_class;
 
-void g_timer_reset( GTimer  *timer );
+  object_class = (GtkObjectClass*) class;
+  
+  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
+                                        GTK_RUN_FIRST,
+                                        object_class->type,
+                                        GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
+                                        gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
 
-gdouble g_timer_elapsed( GTimer *timer,
-                         gulong *microseconds );
-</verb></tscreen>                       
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>String Handling
-<p>
-A whole mess of string handling functions. They all look very interesting, and
-probably better for many purposes than the standard C string functions, but
-require documentation.
+  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
 
-<tscreen><verb>
-GString *g_string_new( gchar *init );
+  class->tictactoe = NULL;
+}
+</verb></tscreen>
 
-void g_string_free( GString *string,
-                    gint     free_segment );
-                            
-GString *g_string_assign( GString *lval,
-                          gchar   *rval );
-                            
-GString *g_string_truncate( GString *string,
-                            gint     len );
-                            
-GString *g_string_append( GString *string,
-                          gchar   *val );
-                           
-GString *g_string_append_c( GString *string,
-                            gchar    c );
-       
-GString *g_string_prepend( GString *string,
-                           gchar   *val );
-                            
-GString *g_string_prepend_c( GString *string,
-                             gchar    c );
-       
-void g_string_sprintf( GString *string,
-                       gchar   *fmt,
-                       ...);
-       
-void g_string_sprintfa ( GString *string,
-                         gchar   *fmt,
-                         ... );
-</verb></tscreen>                                                        
+Our widget has just one signal, the <tt/tictactoe/ signal that is
+invoked when a row, column, or diagonal is completely filled in. Not
+every composite widget needs signals, so if you are reading this for
+the first time, you may want to skip to the next section now, as
+things are going to get a bit complicated.
+
+The function:
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Utility and Error Functions
-<p>
 <tscreen><verb>
-gchar *g_strdup( const gchar *str );
+gint gtk_signal_new( const gchar         *name,
+                     GtkSignalRunType     run_type,
+                     GtkType              object_type,
+                     gint                 function_offset,
+                     GtkSignalMarshaller  marshaller,
+                     GtkType              return_val,
+                     guint                nparams,
+                     ...);
 </verb></tscreen>
 
-Replacement strdup function.  Copies the original strings contents to
-newly allocated memory, and returns a pointer to it.
+Creates a new signal. The parameters are:
 
-<tscreen><verb>
-gchar *g_strerror( gint errnum );
-</verb></tscreen>
+<itemize>
+<item> <tt/name/: The name of the signal.
+<item> <tt/run_type/: Whether the default handler runs before or after
+user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
+although there are other possibilities.
+<item> <tt/object_type/: The ID of the object that this signal applies
+to. (It will also apply to that objects descendents)
+<item> <tt/function_offset/: The offset within the class structure of
+a pointer to the default handler.
+<item> <tt/marshaller/: A function that is used to invoke the signal
+handler. For signal handlers that have no arguments other than the
+object that emitted the signal and user data, we can use the
+pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
+<item> <tt/return_val/: The type of the return val.
+<item> <tt/nparams/: The number of parameters of the signal handler
+(other than the two default ones mentioned above)
+<item> <tt/.../: The types of the parameters.
+</itemize>
 
-I recommend using this for all error messages.  It's much nicer, and more
-portable than perror() or others.  The output is usually of the form:
+When specifying types, the <tt/GtkType/ enumeration is used:
 
 <tscreen><verb>
-program name:function that failed:file or further description:strerror
-</verb></tscreen>
+typedef enum
+{
+  GTK_TYPE_INVALID,
+  GTK_TYPE_NONE,
+  GTK_TYPE_CHAR,
+  GTK_TYPE_BOOL,
+  GTK_TYPE_INT,
+  GTK_TYPE_UINT,
+  GTK_TYPE_LONG,
+  GTK_TYPE_ULONG,
+  GTK_TYPE_FLOAT,
+  GTK_TYPE_DOUBLE,
+  GTK_TYPE_STRING,
+  GTK_TYPE_ENUM,
+  GTK_TYPE_FLAGS,
+  GTK_TYPE_BOXED,
+  GTK_TYPE_FOREIGN,
+  GTK_TYPE_CALLBACK,
+  GTK_TYPE_ARGS,
 
-Here's an example of one such call used in our hello_world program:
+  GTK_TYPE_POINTER,
 
-<tscreen><verb>
-g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
-</verb></tscreen>
+  /* it'd be great if the next two could be removed eventually */
+  GTK_TYPE_SIGNAL,
+  GTK_TYPE_C_CALLBACK,
 
-<tscreen><verb>
-void g_error( gchar *format, ... );
+  GTK_TYPE_OBJECT
+
+} GtkFundamentalType;
 </verb></tscreen>
 
-Prints an error message. The format is just like printf, but it
-prepends "** ERROR **: " to your message, and exits the program.  
-Use only for fatal errors.
+<tt/gtk_signal_new()/ returns a unique integer identifier for the
+signal, that we store in the <tt/tictactoe_signals/ array, which we
+index using an enumeration. (Conventionally, the enumeration elements
+are the signal name, uppercased, but here there would be a conflict
+with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
+instead.
+
+After creating our signals, we need to tell GTK to associate our
+signals with the Tictactoe class. We do that by calling
+<tt/gtk_object_class_add_signals()/. We then set the pointer which
+points to the default handler for the ``tictactoe'' signal to NULL,
+indicating that there is no default action.
+
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <tt/_init()/ function.
+<p>
+Each widget class also needs a function to initialize the object
+structure. Usually, this function has the fairly limited role of
+setting the fields of the structure to default values. For composite
+widgets, however, this function also creates the component widgets.
 
 <tscreen><verb>
-void g_warning( gchar *format, ... );
+static void
+tictactoe_init (Tictactoe *ttt)
+{
+  GtkWidget *table;
+  gint i,j;
+  
+  table = gtk_table_new (3, 3, TRUE);
+  gtk_container_add (GTK_CONTAINER(ttt), table);
+  gtk_widget_show (table);
+
+  for (i=0;i<3; i++)
+    for (j=0;j<3; j++)
+      {
+       ttt->buttons[i][j] = gtk_toggle_button_new ();
+       gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
+                                  i, i+1, j, j+1);
+       gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
+                           GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
+       gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
+       gtk_widget_show (ttt->buttons[i][j]);
+      }
+}
 </verb></tscreen>
 
-Same as above, but prepends "** WARNING **: ", and does not exit the
-program.
-
-<tscreen><verb>
-void g_message( gchar *format, ... );
-</verb></tscreen>
+<!-- ----------------------------------------------------------------- -->
+<sect2> And the rest...
+<p>
+There is one more function that every widget (except for base widget
+types like GtkBin that cannot be instantiated) needs to have - the
+function that the user calls to create an object of that type. This is
+conventionally called <tt/WIDGETNAME_new()/. In some
+widgets, though not for the Tictactoe widgets, this function takes
+arguments, and does some setup based on the arguments. The other two
+functions are specific to the Tictactoe widget. 
 
-Prints "message: " prepended to the string you pass in.
+<tt/tictactoe_clear()/ is a public function that resets all the
+buttons in the widget to the up position. Note the use of
+<tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
+button toggles from being triggered unnecessarily.
 
-<tscreen><verb>
-void g_print( gchar *format, ... );
-</verb></tscreen>
+<tt/tictactoe_toggle()/ is the signal handler that is invoked when the
+user clicks on a button. It checks to see if there are any winning
+combinations that involve the toggled button, and if so, emits
+the "tictactoe" signal.
 
-Replacement for printf().
+<tscreen><verb>  
+GtkWidget*
+tictactoe_new ()
+{
+  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+}
 
-And our last function:
+void          
+tictactoe_clear (Tictactoe *ttt)
+{
+  int i,j;
 
-<tscreen><verb>
-gchar *g_strsignal( gint signum );
-</verb></tscreen>
+  for (i=0;i<3;i++)
+    for (j=0;j<3;j++)
+      {
+       gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
+                                    FALSE);
+       gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+      }
+}
 
-Prints out the name of the Unix system signal given the signal number.
-Useful in generic signal handling functions.
+static void
+tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+{
+  int i,k;
 
-All of the above are more or less just stolen from glib.h.  If anyone cares
-to document any function, just send me an email!
+  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 } };
+  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 2, 1, 0 } };
 
-<!-- ***************************************************************** -->
-<sect>GTK's rc Files
-<!-- ***************************************************************** -->
-<p>
-GTK has it's own way of dealing with application defaults, by using rc
-files. These can be used to set the colors of just about any widget, and
-can also be used to tile pixmaps onto the background of some widgets.  
+  int success, found;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Functions For rc Files 
-<p>
-When your application starts, you should include a call to:
+  for (k=0; k<8; k++)
+    {
+      success = TRUE;
+      found = FALSE;
 
-<tscreen><verb>
-void gtk_rc_parse( char *filename );
+      for (i=0;i<3;i++)
+       {
+         success = success &amp;&amp; 
+           GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
+         found = found ||
+           ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
+       }
+      
+      if (success &amp;&amp; found)
+       {
+         gtk_signal_emit (GTK_OBJECT (ttt), 
+                          tictactoe_signals[TICTACTOE_SIGNAL]);
+         break;
+       }
+    }
+}
 </verb></tscreen>
 
-Passing in the filename of your rc file.  This will cause GTK to parse this
-file, and use the style settings for the widget types defined there.
-
-If you wish to have a special set of widgets that can take on a different
-style from others, or any other logical division of widgets, use a call to:
+And finally, an example program using our Tictactoe widget:
 
 <tscreen><verb>
-void gtk_widget_set_name( GtkWidget *widget,
-                          gchar     *name );
-</verb></tscreen>
-
-Passing your newly created widget as the first argument, and the name
-you wish to give it as the second. This will allow you to change the
-attributes of this widget by name through the rc file.
+#include <gtk/gtk.h>
+#include "tictactoe.h"
 
-If we use a call something like this:
+/* Invoked when a row, column or diagonal is completed */
+void
+win (GtkWidget *widget, gpointer data)
+{
+  g_print ("Yay!\n");
+  tictactoe_clear (TICTACTOE (widget));
+}
 
-<tscreen><verb>
-button = gtk_button_new_with_label ("Special Button");
-gtk_widget_set_name (button, "special button");
-</verb></tscreen>
+int 
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *ttt;
+  
+  gtk_init (&amp;argc, &amp;argv);
 
-Then this button is given the name "special button" and may be addressed by
-name in the rc file as "special button.GtkButton".  [<--- Verify ME!]
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  
+  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
+  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+  
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
 
-The example rc file below, sets the properties of the main window, and lets
-all children of that main window inherit the style described by the "main
-button" style.  The code used in the application is:
+  /* Create a new Tictactoe widget */
+  ttt = tictactoe_new ();
+  gtk_container_add (GTK_CONTAINER (window), ttt);
+  gtk_widget_show (ttt);
 
-<tscreen><verb>
-window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-gtk_widget_set_name (window, "main window");
-</verb></tscreen>
+  /* And attach to its "tictactoe" signal */
+  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
+                     GTK_SIGNAL_FUNC (win), NULL);
 
-And then the style is defined in the rc file using:
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
 
-<tscreen><verb>
-widget "main window.*GtkButton*" style "main_button"
 </verb></tscreen>
 
-Which sets all the GtkButton widgets in the "main window" to the
-"main_buttons" style as defined in the rc file.
-
-As you can see, this is a fairly powerful and flexible system.  Use your
-imagination as to how best to take advantage of this.
+<!-- ----------------------------------------------------------------- -->
+<sect1> Creating a widget from scratch.
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>GTK's rc File Format
+<sect2> Introduction
 <p>
-The format of the GTK file is illustrated in the example below. This is
-the testgtkrc file from the GTK distribution, but I've added a
-few comments and things. You may wish to include this explanation
-your application to allow the user to fine tune his application.
-
-There are several directives to change the attributes of a widget.
-
-<itemize>
-<item>fg - Sets the foreground color of a widget.
-<item>bg - Sets the background color of a widget.
-<item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
-<item>font - Sets the font to be used with the given widget.
-</itemize>
+In this section, we'll learn more about how widgets display themselves
+on the screen and interact with events. As an example of this, we'll
+create an analog dial widget with a pointer that the user can drag to
+set the value.
 
-In addition to this, there are several states a widget can be in, and you
-can set different colors, pixmaps and fonts for each state. These states are:
+<!-- ----------------------------------------------------------------- -->
+<sect2> Displaying a widget on the screen
+<p>
+There are several steps that are involved in displaying on the screen.
+After the widget is created with a call to <tt/WIDGETNAME_new()/,
+several more functions are needed:
 
 <itemize>
-<item>NORMAL - The normal state of a widget, without the mouse over top of
-it, and not being pressed etc.
-<item>PRELIGHT - When the mouse is over top of the widget, colors defined
-using this state will be in effect.
-<item>ACTIVE - When the widget is pressed or clicked it will be active, and
-the attributes assigned by this tag will be in effect.
-<item>INSENSITIVE - When a widget is set insensitive, and cannot be
-activated, it will take these attributes.
-<item>SELECTED - When an object is selected, it takes these attributes.
+<item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
+window for the widget if it has one.
+<item> <tt/WIDGETNAME_map()/ is invoked after the user calls
+<tt/gtk_widget_show()/. It is responsible for making sure the widget
+is actually drawn on the screen (<em/mapped/). For a container class,
+it must also make calls to <tt/map()/> functions of any child widgets.
+<item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
+is called for the widget or one of its ancestors. It makes the actual
+calls to the drawing functions to draw the widget on the screen. For
+container widgets, this function must make calls to
+<tt/gtk_widget_draw()/ for its child widgets.
+<item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
+widget. It makes the necessary calls to the drawing functions to draw
+the exposed portion on the screen. For container widgets, this
+function must generate expose events for its child widgets which don't
+have their own windows. (If they have their own windows, then X will
+generate the necessary expose events)
 </itemize>
 
-When using the "fg" and "bg" keywords to set the colors of widgets, the
-format is:
+You might notice that the last two functions are quite similar - each
+is responsible for drawing the widget on the screen. In fact many
+types of widgets don't really care about the difference between the
+two. The default <tt/draw()/ function in the widget class simply
+generates a synthetic expose event for the redrawn area. However, some
+types of widgets can save work by distinguishing between the two
+functions. For instance, if a widget has multiple X windows, then
+since expose events identify the exposed window, it can redraw only
+the affected window, which is not possible for calls to <tt/draw()/.
 
-<tscreen><verb>
-fg[<STATE>] = { Red, Green, Blue }
-</verb></tscreen>
+Container widgets, even if they don't care about the difference for
+themselves, can't simply use the default <tt/draw()/ function because
+their child widgets might care about the difference. However,
+it would be wasteful to duplicate the drawing code between the two
+functions. The convention is that such widgets have a function called
+<tt/WIDGETNAME_paint()/ that does the actual work of drawing the
+widget, that is then called by the <tt/draw()/ and <tt/expose()/
+functions.
 
-Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
-Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
-white. They must be in float form, or they will register as 0, so a straight 
-"1" will not work, it must be "1.0".  A straight "0" is fine because it 
-doesn't matter if it's not recognized.  Unrecognized values are set to 0.
+In our example approach, since the dial widget is not a container
+widget, and only has a single window, we can take the simplest
+approach and use the default <tt/draw()/ function and only implement
+an <tt/expose()/ function.
 
-bg_pixmap is very similar to the above, except the colors are replaced by a
-filename.
+<!-- ----------------------------------------------------------------- -->
+<sect2> The origins of the Dial Widget
+<p>
+Just as all land animals are just variants on the first amphibian that
+crawled up out of the mud, Gtk widgets tend to start off as variants
+of some other, previously written widget.  Thus, although this section
+is entilted ``Creating a Widget from Scratch'', the Dial widget really
+began with the source code for the Range widget. This was picked as a
+starting point because it would be nice if our Dial had the same
+interface as the Scale widgets which are just specialized descendents
+of the Range widget. So, though the source code is presented below in
+finished form, it should not be implied that it was written, <em>deus
+ex machina</em> in this fashion. Also, if you aren't yet familiar with
+how scale widgets work from the application writer's point of view, it
+would be a good idea to look them over before continuing.
 
-pixmap_path is a list of paths seperated by ":"'s.  These paths will be
-searched for any pixmap you specify.
+<!-- ----------------------------------------------------------------- -->
+<sect2> The Basics
+<p>
+Quite a bit of our widget should look pretty familiar from the
+Tictactoe widget. First, we have a header file:
 
-The font directive is simply:
 <tscreen><verb>
-font = "<font name>"
-</verb></tscreen>
-
-Where the only hard part is figuring out the font string. Using xfontsel or
-similar utility should help.
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
-The "widget_class" sets the style of a class of widgets. These classes are
-listed in the widget overview on the class hierarchy.
+#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__
 
-The "widget" directive sets a specificaly named set of widgets to a
-given style, overriding any style set for the given widget class.
-These widgets are registered inside the application using the
-gtk_widget_set_name() call. This allows you to specify the attributes of a
-widget on a per widget basis, rather than setting the attributes of an
-entire widget class. I urge you to document any of these special widgets so
-users may customize them.
+#include <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
 
-When the keyword <tt>parent</> is used as an attribute, the widget will take on
-the attributes of it's parent in the application.
 
-When defining a style, you may assign the attributes of a previously defined
-style to this new one.
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
-<tscreen><verb>
-style "main_button" = "button"
-{
-  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
-  bg[PRELIGHT] = { 0.75, 0, 0 }
-}
-</verb></tscreen>
 
-This example takes the "button" style, and creates a new "main_button" style
-simply by changing the font and prelight background color of the "button"
-style.
+#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
 
-Of course, many of these attributes don't apply to all widgets. It's a
-simple matter of common sense really. Anything that could apply, should.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Example rc file
-<p>
+typedef struct _GtkDial        GtkDial;
+typedef struct _GtkDialClass   GtkDialClass;
 
-<tscreen><verb>
-# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
-#
-pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
-#
-# style <name> [= <name>]
-# {
-#   <option>
-# }
-#
-# widget <widget_set> style <style_name>
-# widget_class <widget_class_set> style <style_name>
+struct _GtkDial
+{
+  GtkWidget widget;
 
+  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+  guint policy : 2;
 
-# Here is a list of all the possible states.  Note that some do not apply to
-# certain widgets.
-#
-# NORMAL - The normal state of a widget, without the mouse over top of
-# it, and not being pressed etc.
-#
-# PRELIGHT - When the mouse is over top of the widget, colors defined
-# using this state will be in effect.
-#
-# ACTIVE - When the widget is pressed or clicked it will be active, and
-# the attributes assigned by this tag will be in effect.
-#
-# INSENSITIVE - When a widget is set insensitive, and cannot be
-# activated, it will take these attributes.
-#
-# SELECTED - When an object is selected, it takes these attributes.
-#
-# Given these states, we can set the attributes of the widgets in each of
-# these states using the following directives.
-#
-# fg - Sets the foreground color of a widget.
-# fg - Sets the background color of a widget.
-# bg_pixmap - Sets the background of a widget to a tiled pixmap.
-# font - Sets the font to be used with the given widget.
-#
+  /* Button currently pressed or 0 if none */
+  guint8 button;
 
-# This sets a style called "button".  The name is not really important, as
-# it is assigned to the actual widgets at the bottom of the file.
+  /* Dimensions of dial components */
+  gint radius;
+  gint pointer_width;
 
-style "window"
-{
-  #This sets the padding around the window to the pixmap specified.
-  #bg_pixmap[<STATE>] = "<pixmap filename>"
-  bg_pixmap[NORMAL] = "warning.xpm"
-}
+  /* ID of update timer, or 0 if none */
+  guint32 timer;
 
-style "scale"
-{
-  #Sets the foreground color (font color) to red when in the "NORMAL"
-  #state.
-  
-  fg[NORMAL] = { 1.0, 0, 0 }
-  
-  #Sets the background pixmap of this widget to that of it's parent.
-  bg_pixmap[NORMAL] = "<parent>"
-}
+  /* Current angle */
+  gfloat angle;
 
-style "button"
-{
-  # This shows all the possible states for a button.  The only one that
-  # doesn't apply is the SELECTED state.
-  
-  fg[PRELIGHT] = { 0, 1.0, 1.0 }
-  bg[PRELIGHT] = { 0, 0, 1.0 }
-  bg[ACTIVE] = { 1.0, 0, 0 }
-  fg[ACTIVE] = { 0, 1.0, 0 }
-  bg[NORMAL] = { 1.0, 1.0, 0 }
-  fg[NORMAL] = { .99, 0, .99 }
-  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
-  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
-}
+  /* Old values from adjustment stored so we know when something changes */
+  gfloat old_value;
+  gfloat old_lower;
+  gfloat old_upper;
 
-# In this example, we inherit the attributes of the "button" style and then
-# override the font and background color when prelit to create a new
-# "main_button" style.
+  /* The adjustment object that stores the data for this dial */
+  GtkAdjustment *adjustment;
+};
 
-style "main_button" = "button"
+struct _GtkDialClass
 {
-  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
-  bg[PRELIGHT] = { 0.75, 0, 0 }
-}
+  GtkWidgetClass parent_class;
+};
 
-style "toggle_button" = "button"
-{
-  fg[NORMAL] = { 1.0, 0, 0 }
-  fg[ACTIVE] = { 1.0, 0, 0 }
-  
-  # This sets the background pixmap of the toggle_button to that of it's
-  # parent widget (as defined in the application).
-  bg_pixmap[NORMAL] = "<parent>"
-}
 
-style "text"
-{
-  bg_pixmap[NORMAL] = "marble.xpm"
-  fg[NORMAL] = { 1.0, 1.0, 1.0 }
-}
+GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
+guint          gtk_dial_get_type               (void);
+GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
+void           gtk_dial_set_update_policy      (GtkDial      *dial,
+                                               GtkUpdateType  policy);
 
-style "ruler"
-{
-  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+void           gtk_dial_set_adjustment         (GtkDial      *dial,
+                                               GtkAdjustment *adjustment);
+#ifdef __cplusplus
 }
+#endif /* __cplusplus */
 
-# pixmap_path "~/.pixmaps"
 
-# These set the widget types to use the styles defined above.
-# The widget types are listed in the class hierarchy, but could probably be
-# just listed in this document for the users reference.
+#endif /* __GTK_DIAL_H__ */
+</verb></tscreen>
 
-widget_class "GtkWindow" style "window"
-widget_class "GtkDialog" style "window"
-widget_class "GtkFileSelection" style "window"
-widget_class "*Gtk*Scale" style "scale"
-widget_class "*GtkCheckButton*" style "toggle_button"
-widget_class "*GtkRadioButton*" style "toggle_button"
-widget_class "*GtkButton*" style "button"
-widget_class "*Ruler" style "ruler"
-widget_class "*GtkText" style "text"
+Since there is quite a bit more going on in this widget, than the last
+one, we have more fields in the data structure, but otherwise things
+are pretty similar.
 
-# This sets all the buttons that are children of the "main window" to
-# the main_buton style.  These must be documented to be taken advantage of.
-widget "main window.*GtkButton*" style "main_button"
-</verb></tscreen>
+Next, after including header files, and declaring a few constants,
+we have some functions to provide information about the widget
+and initialize it:
 
-<!-- ***************************************************************** -->
-<sect>Writing Your Own Widgets 
-<!-- ***************************************************************** -->
+<tscreen><verb>
+#include <math.h>
+#include <stdio.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Overview
-<p>
-Although the GTK distribution comes with many types of widgets that
-should cover most basic needs, there may come a time when you need to
-create your own new widget type. Since GTK uses widget inheretence
-extensively, and there is already a widget that is close to what you want,
-it is often possible to make a useful new widget type in
-just a few lines of code. But before starting work on a new widget, check
-around first to make sure that someone has not already written
-it. This will prevent duplication of effort and keep the number of
-GTK widgets out there to a minimum, which will help keep both the code
-and the interface of different applications consistent. As a flip side
-to this, once you finish your widget, announce it to the world so
-other people can benefit. The best place to do this is probably the
-<tt>gtk-list</tt>.
+#include "gtkdial.h"
 
-Complete sources for the example widgets are available at the place you 
-got this tutorial, or from:
+#define SCROLL_DELAY_LENGTH  300
+#define DIAL_DEFAULT_SIZE 100
 
-<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
-name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+/* Forward declararations */
 
+[ omitted to save space ]
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> The Anatomy Of A Widget
-<p>
-In order to create a new widget, it is important to have an
-understanding of how GTK objects work. This section is just meant as a
-brief overview. See the reference documentation for the details. 
+/* Local data */
 
-GTK widgets are implemented in an object oriented fashion. However,
-they are implemented in standard C. This greatly improves portability
-and stability over using current generation C++ compilers; however,
-it does mean that the widget writer has to pay attention to some of
-the implementation details. The information common to all instances of
-one class of widgets (e.g., to all Button widgets) is stored in the 
-<em>class structure</em>. There is only one copy of this in
-which is stored information about the class's signals
-(which act like virtual functions in C). To support inheritance, the
-first field in the class structure must be a copy of the parent's
-class structure. The declaration of the class structure of GtkButtton
-looks like:
+static GtkWidgetClass *parent_class = NULL;
 
-<tscreen><verb>
-struct _GtkButtonClass
+guint
+gtk_dial_get_type ()
 {
-  GtkContainerClass parent_class;
+  static guint dial_type = 0;
 
-  void (* pressed)  (GtkButton *button);
-  void (* released) (GtkButton *button);
-  void (* clicked)  (GtkButton *button);
-  void (* enter)    (GtkButton *button);
-  void (* leave)    (GtkButton *button);
-};
-</verb></tscreen>
+  if (!dial_type)
+    {
+      GtkTypeInfo dial_info =
+      {
+       "GtkDial",
+       sizeof (GtkDial),
+       sizeof (GtkDialClass),
+       (GtkClassInitFunc) gtk_dial_class_init,
+       (GtkObjectInitFunc) gtk_dial_init,
+       (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL,
+      };
 
-When a button is treated as a container (for instance, when it is
-resized), its class structure can be cast to GtkContainerClass, and
-the relevant fields used to handle the signals.
+      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+    }
 
-There is also a structure for each widget that is created on a
-per-instance basis. This structure has fields to store information that
-is different for each instance of the widget. We'll call this
-structure the <em>object structure</em>. For the Button class, it looks
-like:
+  return dial_type;
+}
 
-<tscreen><verb>
-struct _GtkButton
+static void
+gtk_dial_class_init (GtkDialClass *class)
 {
-  GtkContainer container;
-
-  GtkWidget *child;
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
 
-  guint in_button : 1;
-  guint button_down : 1;
-};
-</verb></tscreen>
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
 
-Note that, similar to the class structure, the first field is the
-object structure of the parent class, so that this structure can be
-cast to the parent class's object structure as needed.
+  parent_class = gtk_type_class (gtk_widget_get_type ());
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Creating a Composite widget
+  object_class->destroy = gtk_dial_destroy;
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Introduction
-<p>
-One type of widget that you may be interested in creating is a
-widget that is merely an aggregate of other GTK widgets. This type of
-widget does nothing that couldn't be done without creating new
-widgets, but provides a convenient way of packaging user interface
-elements for reuse. The FileSelection and ColorSelection widgets in
-the standard distribution are examples of this type of widget.
+  widget_class->realize = gtk_dial_realize;
+  widget_class->expose_event = gtk_dial_expose;
+  widget_class->size_request = gtk_dial_size_request;
+  widget_class->size_allocate = gtk_dial_size_allocate;
+  widget_class->button_press_event = gtk_dial_button_press;
+  widget_class->button_release_event = gtk_dial_button_release;
+  widget_class->motion_notify_event = gtk_dial_motion_notify;
+}
 
-The example widget that we'll create in this section is the Tictactoe
-widget, a 3x3 array of toggle buttons which triggers a signal when all
-three buttons in a row, column, or on one of the diagonals are
-depressed. 
+static void
+gtk_dial_init (GtkDial *dial)
+{
+  dial->button = 0;
+  dial->policy = GTK_UPDATE_CONTINUOUS;
+  dial->timer = 0;
+  dial->radius = 0;
+  dial->pointer_width = 0;
+  dial->angle = 0.0;
+  dial->old_value = 0.0;
+  dial->old_lower = 0.0;
+  dial->old_upper = 0.0;
+  dial->adjustment = NULL;
+}
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Choosing a parent class
-<p>
-The parent class for a composite widget is typically the container
-class that holds all of the elements of the composite widget. For
-example, the parent class of the FileSelection widget is the
-Dialog class. Since our buttons will be arranged in a table, it
-might seem natural to make our parent class the GtkTable
-class. Unfortunately, this turns out not to work. The creation of a
-widget is divided among two functions - a <tt/WIDGETNAME_new()/
-function that the user calls, and a <tt/WIDGETNAME_init()/ function
-which does the basic work of initializing the widget which is
-independent of the arguments passed to the <tt/_new()/
-function. Descendent widgets only call the <tt/_init/ function of
-their parent widget. But this division of labor doesn't work well for
-tables, which when created, need to know the number of rows and
-columns in the table. Unless we want to duplicate most of the
-functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
-best avoid deriving it from GtkTable. For that reason, we derive it
-from GtkVBox instead, and stick our table inside the VBox.
+GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+  GtkDial *dial;
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The header file
-<p>
-Each widget class has a header file which declares the object and
-class structures for that widget, along with public functions. 
-A couple of features are worth pointing out. To prevent duplicate
-definitions, we wrap the entire header file in:
+  dial = gtk_type_new (gtk_dial_get_type ());
 
-<tscreen><verb>
-#ifndef __TICTACTOE_H__
-#define __TICTACTOE_H__
-.
-.
-.
-#endif /* __TICTACTOE_H__ */
-</verb></tscreen>
+  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
-And to keep C++ programs that include the header file happy, in:
+  gtk_dial_set_adjustment (dial, adjustment);
 
-<tscreen><verb>
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-.
-.
-.
-#ifdef __cplusplus
+  return GTK_WIDGET (dial);
 }
-#endif /* __cplusplus */
-</verb></tscreen>
 
-Along with the functions and structures, we declare three standard
-macros in our header file, <tt/TICTACTOE(obj)/,
-<tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
-pointer into a pointer to the object or class structure, and check
-if an object is a Tictactoe widget respectively.
+static void
+gtk_dial_destroy (GtkObject *object)
+{
+  GtkDial *dial;
 
-Here is the complete header file:
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_DIAL (object));
 
-<tscreen><verb>
-/* tictactoe.h */
+  dial = GTK_DIAL (object);
 
-#ifndef __TICTACTOE_H__
-#define __TICTACTOE_H__
+  if (dial->adjustment)
+    gtk_object_unref (GTK_OBJECT (dial->adjustment));
 
-#include <gdk/gdk.h>
-#include <gtk/gtkvbox.h>
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+</verb></tscreen>
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+Note that this <tt/init()/ function does less than for the Tictactoe
+widget, since this is not a composite widget, and the <tt/new()/
+function does more, since it now has an argument. Also, note that when
+we store a pointer to the Adjustment object, we increment its
+reference count, (and correspondingly decrement when we no longer use
+it) so that GTK can keep track of when it can be safely destroyed.
 
-#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
-#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
-#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
+<p>
+Also, there are a few function to manipulate the widget's options:
 
+<tscreen><verb>
+GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
 
-typedef struct _Tictactoe       Tictactoe;
-typedef struct _TictactoeClass  TictactoeClass;
+  return dial->adjustment;
+}
 
-struct _Tictactoe
+void
+gtk_dial_set_update_policy (GtkDial      *dial,
+                            GtkUpdateType  policy)
 {
-  GtkVBox vbox;
-  
-  GtkWidget *buttons[3][3];
-};
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  dial->policy = policy;
+}
 
-struct _TictactoeClass
+void
+gtk_dial_set_adjustment (GtkDial      *dial,
+                         GtkAdjustment *adjustment)
 {
-  GtkVBoxClass parent_class;
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-  void (* tictactoe) (Tictactoe *ttt);
-};
+  if (dial->adjustment)
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+      gtk_object_unref (GTK_OBJECT (dial->adjustment));
+    }
 
-guint          tictactoe_get_type        (void);
-GtkWidget*     tictactoe_new             (void);
-void          tictactoe_clear           (Tictactoe *ttt);
+  dial->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (dial->adjustment));
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_changed,
+                     (gpointer) dial);
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+                     (gpointer) dial);
 
-#endif /* __TICTACTOE_H__ */
+  dial->old_value = adjustment->value;
+  dial->old_lower = adjustment->lower;
+  dial->old_upper = adjustment->upper;
 
+  gtk_dial_update (dial);
+}
 </verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The <tt/_get_type()/ function.
+<sect2> <tt/gtk_dial_realize()/
+
 <p>
-We now continue on to the implementation of our widget. A core
-function for every widget is the function
-<tt/WIDGETNAME_get_type()/. This function, when first called, tells
-GTK about the widget class, and gets an ID that uniquely identifies
-the widget class. Upon subsequent calls, it just returns the ID.
+Now we come to some new types of functions. First, we have a function
+that does the work of creating the X window. Notice that a mask is
+passed to the function <tt/gdk_window_new()/ which specifies which fields of
+the GdkWindowAttr structure actually have data in them (the remaining
+fields wll be given default values). Also worth noting is the way the
+event mask of the widget is created. We call
+<tt/gtk_widget_get_events()/ to retrieve the event mask that the user
+has specified for this widget (with <tt/gtk_widget_set_events()/, and
+add the events that we are interested in ourselves.
+
+<p>
+After creating the window, we set its style and background, and put a
+pointer to the widget in the user data field of the GdkWindow. This
+last step allows GTK to dispatch events for this window to the correct
+widget.
 
 <tscreen><verb>
-guint
-tictactoe_get_type ()
+static void
+gtk_dial_realize (GtkWidget *widget)
 {
-  static guint ttt_type = 0;
+  GtkDial *dial;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
 
-  if (!ttt_type)
-    {
-      GtkTypeInfo ttt_info =
-      {
-       "Tictactoe",
-       sizeof (Tictactoe),
-       sizeof (TictactoeClass),
-       (GtkClassInitFunc) tictactoe_class_init,
-       (GtkObjectInitFunc) tictactoe_init,
-       (GtkArgSetFunc) NULL,
-        (GtkArgGetFunc) NULL
-      };
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
 
-      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
-    }
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  dial = GTK_DIAL (widget);
 
-  return ttt_type;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+
+  gdk_window_set_user_data (widget->window, widget);
+
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
 }
 </verb></tscreen>
 
-The GtkTypeInfo structure has the following definition:
+<sect2> Size negotiation
+
+<p>
+Before the first time that the window containing a widget is
+displayed, and whenever the layout of the window changes, GTK asks
+each child widget for its desired size. This request is handled by the
+function, <tt/gtk_dial_size_request()/. Since our widget isn't a
+container widget, and has no real constraints on its size, we just
+return a reasonable default value.
 
 <tscreen><verb>
-struct _GtkTypeInfo
+static void 
+gtk_dial_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
 {
-  gchar *type_name;
-  guint object_size;
-  guint class_size;
-  GtkClassInitFunc class_init_func;
-  GtkObjectInitFunc object_init_func;
-  GtkArgSetFunc arg_set_func;
-  GtkArgGetFunc arg_get_func;
-};
+  requisition->width = DIAL_DEFAULT_SIZE;
+  requisition->height = DIAL_DEFAULT_SIZE;
+}
 </verb></tscreen>
 
-The fields of this structure are pretty self-explanatory. We'll ignore
-the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important, 
-but as yet largely
-unimplemented, role in allowing widget options to be conveniently set
-from interpreted languages. Once GTK has a correctly filled in copy of
-this structure, it knows how to create objects of a particular widget
-type. 
-
-<!-- ----------------------------------------------------------------- -->
-<sect2> The <tt/_class_init()/ function
 <p>
-The <tt/WIDGETNAME_class_init()/ function initializes the fields of
-the widget's class structure, and sets up any signals for the
-class. For our Tictactoe widget it looks like:
+After all the widgets have requested an ideal size, the layout of the
+window is computed and each child widget is notified of its actual
+size. Usually, this will at least as large as the requested size, but
+if for instance, the user has resized the window, it may occasionally
+be smaller than the requested size. The size notification is handled
+by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
+computing the sizes of some component pieces for future use, this
+routine also does the grunt work of moving the widgets X window into
+the new position and size.
 
 <tscreen><verb>
-
-enum {
-  TICTACTOE_SIGNAL,
-  LAST_SIGNAL
-};
-
-static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
-
 static void
-tictactoe_class_init (TictactoeClass *class)
+gtk_dial_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
 {
-  GtkObjectClass *object_class;
+  GtkDial *dial;
 
-  object_class = (GtkObjectClass*) class;
-  
-  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
-                                        GTK_RUN_FIRST,
-                                        object_class->type,
-                                        GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
-                                        gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+  g_return_if_fail (allocation != NULL);
 
+  widget->allocation = *allocation;
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      dial = GTK_DIAL (widget);
 
-  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
+      gdk_window_move_resize (widget->window,
+                             allocation->x, allocation->y,
+                             allocation->width, allocation->height);
 
-  class->tictactoe = NULL;
+      dial->radius = MAX(allocation->width,allocation->height) * 0.45;
+      dial->pointer_width = dial->radius / 5;
+    }
 }
-</verb></tscreen>
+</verb></tscreen>.
 
-Our widget has just one signal, the <tt/tictactoe/ signal that is
-invoked when a row, column, or diagonal is completely filled in. Not
-every composite widget needs signals, so if you are reading this for
-the first time, you may want to skip to the next section now, as
-things are going to get a bit complicated.
+<!-- ----------------------------------------------------------------- -->
+<sect2> <tt/gtk_dial_expose()/
 
-The function:
+<p>
+As mentioned above, all the drawing of this widget is done in the
+handler for expose events. There's not much to remark on here except
+the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
+three dimensional shading according to the colors stored in the
+widget's style.
 
 <tscreen><verb>
-gint gtk_signal_new( const gchar         *name,
-                     GtkSignalRunType     run_type,
-                     GtkType              object_type,
-                     gint                 function_offset,
-                     GtkSignalMarshaller  marshaller,
-                     GtkType              return_val,
-                     guint                nparams,
-                     ...);
-</verb></tscreen>
+static gint
+gtk_dial_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
+{
+  GtkDial *dial;
+  GdkPoint points[3];
+  gdouble s,c;
+  gdouble theta;
+  gint xc, yc;
+  gint tick_length;
+  gint i;
 
-Creates a new signal. The parameters are:
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-<itemize>
-<item> <tt/name/: The name of the signal.
-<item> <tt/run_type/: Whether the default handler runs before or after
-user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
-although there are other possibilities.
-<item> <tt/object_type/: The ID of the object that this signal applies
-to. (It will also apply to that objects descendents)
-<item> <tt/function_offset/: The offset within the class structure of
-a pointer to the default handler.
-<item> <tt/marshaller/: A function that is used to invoke the signal
-handler. For signal handlers that have no arguments other than the
-object that emitted the signal and user data, we can use the
-pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
-<item> <tt/return_val/: The type of the return val.
-<item> <tt/nparams/: The number of parameters of the signal handler
-(other than the two default ones mentioned above)
-<item> <tt/.../: The types of the parameters.
-</itemize>
+  if (event->count > 0)
+    return FALSE;
+  
+  dial = GTK_DIAL (widget);
 
-When specifying types, the <tt/GtkType/ enumeration is used:
+  gdk_window_clear_area (widget->window,
+                        0, 0,
+                        widget->allocation.width,
+                        widget->allocation.height);
 
-<tscreen><verb>
-typedef enum
-{
-  GTK_TYPE_INVALID,
-  GTK_TYPE_NONE,
-  GTK_TYPE_CHAR,
-  GTK_TYPE_BOOL,
-  GTK_TYPE_INT,
-  GTK_TYPE_UINT,
-  GTK_TYPE_LONG,
-  GTK_TYPE_ULONG,
-  GTK_TYPE_FLOAT,
-  GTK_TYPE_DOUBLE,
-  GTK_TYPE_STRING,
-  GTK_TYPE_ENUM,
-  GTK_TYPE_FLAGS,
-  GTK_TYPE_BOXED,
-  GTK_TYPE_FOREIGN,
-  GTK_TYPE_CALLBACK,
-  GTK_TYPE_ARGS,
+  xc = widget->allocation.width/2;
+  yc = widget->allocation.height/2;
 
-  GTK_TYPE_POINTER,
+  /* Draw ticks */
 
-  /* it'd be great if the next two could be removed eventually */
-  GTK_TYPE_SIGNAL,
-  GTK_TYPE_C_CALLBACK,
+  for (i=0; i<25; i++)
+    {
+      theta = (i*M_PI/18. - M_PI/6.);
+      s = sin(theta);
+      c = cos(theta);
 
-  GTK_TYPE_OBJECT
+      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
+      
+      gdk_draw_line (widget->window,
+                    widget->style->fg_gc[widget->state],
+                    xc + c*(dial->radius - tick_length),
+                    yc - s*(dial->radius - tick_length),
+                    xc + c*dial->radius,
+                    yc - s*dial->radius);
+    }
 
-} GtkFundamentalType;
-</verb></tscreen>
+  /* Draw pointer */
 
-<tt/gtk_signal_new()/ returns a unique integer identifier for the
-signal, that we store in the <tt/tictactoe_signals/ array, which we
-index using an enumeration. (Conventionally, the enumeration elements
-are the signal name, uppercased, but here there would be a conflict
-with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
-instead.
+  s = sin(dial->angle);
+  c = cos(dial->angle);
 
-After creating our signals, we need to tell GTK to associate our
-signals with the Tictactoe class. We do that by calling
-<tt/gtk_object_class_add_signals()/. We then set the pointer which
-points to the default handler for the ``tictactoe'' signal to NULL,
-indicating that there is no default action.
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The <tt/_init()/ function.
-<p>
-Each widget class also needs a function to initialize the object
-structure. Usually, this function has the fairly limited role of
-setting the fields of the structure to default values. For composite
-widgets, however, this function also creates the component widgets.
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;
 
-<tscreen><verb>
-static void
-tictactoe_init (Tictactoe *ttt)
-{
-  GtkWidget *table;
-  gint i,j;
+  gtk_draw_polygon (widget->style,
+                   widget->window,
+                   GTK_STATE_NORMAL,
+                   GTK_SHADOW_OUT,
+                   points, 3,
+                   TRUE);
   
-  table = gtk_table_new (3, 3, TRUE);
-  gtk_container_add (GTK_CONTAINER(ttt), table);
-  gtk_widget_show (table);
-
-  for (i=0;i<3; i++)
-    for (j=0;j<3; j++)
-      {
-       ttt->buttons[i][j] = gtk_toggle_button_new ();
-       gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
-                                  i, i+1, j, j+1);
-       gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
-                           GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
-       gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
-       gtk_widget_show (ttt->buttons[i][j]);
-      }
+  return FALSE;
 }
 </verb></tscreen>
 
 <!-- ----------------------------------------------------------------- -->
-<sect2> And the rest...
+<sect2> Event handling
+
 <p>
-There is one more function that every widget (except for base widget
-types like GtkBin that cannot be instantiated) needs to have - the
-function that the user calls to create an object of that type. This is
-conventionally called <tt/WIDGETNAME_new()/. In some
-widgets, though not for the Tictactoe widgets, this function takes
-arguments, and does some setup based on the arguments. The other two
-functions are specific to the Tictactoe widget. 
 
-<tt/tictactoe_clear()/ is a public function that resets all the
-buttons in the widget to the up position. Note the use of
-<tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
-button toggles from being triggered unnecessarily.
+The rest of the widget's code handles various types of events, and
+isn't too different from what would be found in many GTK
+applications. Two types of events can occur - either the user can
+click on the widget with the mouse and drag to move the pointer, or
+the value of the Adjustment object can change due to some external
+circumstance. 
 
-<tt/tictactoe_toggle()/ is the signal handler that is invoked when the
-user clicks on a button. It checks to see if there are any winning
-combinations that involve the toggled button, and if so, emits
-the "tictactoe" signal.
+<p>
+When the user clicks on the widget, we check to see if the click was
+appropriately near the pointer, and if so, store then button that the
+user clicked with in the <tt/button/ field of the widget
+structure, and grab all mouse events with a call to
+<tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
+value of the control to be recomputed (by the function
+<tt/gtk_dial_update_mouse/). Depending on the policy that has been
+set, "value_changed" events are either generated instantly
+(<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
+<tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
+button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
 
-<tscreen><verb>  
-GtkWidget*
-tictactoe_new ()
+<tscreen><verb>
+static gint
+gtk_dial_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
 {
-  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+  GtkDial *dial;
+  gint dx, dy;
+  double s, c;
+  double d_parallel;
+  double d_perpendicular;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  /* Determine if button press was within pointer region - we 
+     do this by computing the parallel and perpendicular distance of
+     the point where the mouse was pressed from the line passing through
+     the pointer */
+  
+  dx = event->x - widget->allocation.width / 2;
+  dy = widget->allocation.height / 2 - event->y;
+  
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  
+  d_parallel = s*dy + c*dx;
+  d_perpendicular = fabs(s*dx - c*dy);
+  
+  if (!dial->button &&
+      (d_perpendicular < dial->pointer_width/2) &&
+      (d_parallel > - dial->pointer_width))
+    {
+      gtk_grab_add (widget);
+
+      dial->button = event->button;
+
+      gtk_dial_update_mouse (dial, event->x, event->y);
+    }
+
+  return FALSE;
 }
 
-void          
-tictactoe_clear (Tictactoe *ttt)
+static gint
+gtk_dial_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
 {
-  int i,j;
+  GtkDial *dial;
 
-  for (i=0;i<3;i++)
-    for (j=0;j<3;j++)
-      {
-       gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
-       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
-                                    FALSE);
-       gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
-      }
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  if (dial->button == event->button)
+    {
+      gtk_grab_remove (widget);
+
+      dial->button = 0;
+
+      if (dial->policy == GTK_UPDATE_DELAYED)
+       gtk_timeout_remove (dial->timer);
+      
+      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
+         (dial->old_value != dial->adjustment->value))
+       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
+
+  return FALSE;
 }
 
-static void
-tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+static gint
+gtk_dial_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
 {
-  int i,k;
+  GtkDial *dial;
+  GdkModifierType mods;
+  gint x, y, mask;
 
-  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
-                            { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
-                            { 0, 1, 2 }, { 0, 1, 2 } };
-  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
-                            { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
-                            { 0, 1, 2 }, { 2, 1, 0 } };
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  int success, found;
+  dial = GTK_DIAL (widget);
 
-  for (k=0; k<8; k++)
+  if (dial->button != 0)
     {
-      success = TRUE;
-      found = FALSE;
+      x = event->x;
+      y = event->y;
 
-      for (i=0;i<3;i++)
-       {
-         success = success &amp;&amp; 
-           GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
-         found = found ||
-           ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
-       }
-      
-      if (success &amp;&amp; found)
+      if (event->is_hint || (event->window != widget->window))
+       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
+
+      switch (dial->button)
        {
-         gtk_signal_emit (GTK_OBJECT (ttt), 
-                          tictactoe_signals[TICTACTOE_SIGNAL]);
+       case 1:
+         mask = GDK_BUTTON1_MASK;
+         break;
+       case 2:
+         mask = GDK_BUTTON2_MASK;
+         break;
+       case 3:
+         mask = GDK_BUTTON3_MASK;
+         break;
+       default:
+         mask = 0;
          break;
        }
-    }
-}
-</verb></tscreen>
 
-And finally, an example program using our Tictactoe widget:
-
-<tscreen><verb>
-#include <gtk/gtk.h>
-#include "tictactoe.h"
+      if (mods & mask)
+       gtk_dial_update_mouse (dial, x,y);
+    }
 
-/* Invoked when a row, column or diagonal is completed */
-void
-win (GtkWidget *widget, gpointer data)
-{
-  g_print ("Yay!\n");
-  tictactoe_clear (TICTACTOE (widget));
+  return FALSE;
 }
 
-int 
-main (int argc, char *argv[])
+static gint
+gtk_dial_timer (GtkDial *dial)
 {
-  GtkWidget *window;
-  GtkWidget *ttt;
-  
-  gtk_init (&amp;argc, &amp;argv);
+  g_return_val_if_fail (dial != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
 
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  
-  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
-  
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
-  
-  gtk_container_border_width (GTK_CONTAINER (window), 10);
+  if (dial->policy == GTK_UPDATE_DELAYED)
+    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
-  /* Create a new Tictactoe widget */
-  ttt = tictactoe_new ();
-  gtk_container_add (GTK_CONTAINER (window), ttt);
-  gtk_widget_show (ttt);
+  return FALSE;
+}
 
-  /* And attach to its "tictactoe" signal */
-  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
-                     GTK_SIGNAL_FUNC (win), NULL);
+static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+  gint xc, yc;
+  gfloat old_value;
 
-  gtk_widget_show (window);
-  
-  gtk_main ();
-  
-  return 0;
-}
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-</verb></tscreen>
+  xc = GTK_WIDGET(dial)->allocation.width / 2;
+  yc = GTK_WIDGET(dial)->allocation.height / 2;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Creating a widget from scratch.
+  old_value = dial->adjustment->value;
+  dial->angle = atan2(yc-y, x-xc);
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Introduction
-<p>
-In this section, we'll learn more about how widgets display themselves
-on the screen and interact with events. As an example of this, we'll
-create an analog dial widget with a pointer that the user can drag to
-set the value.
+  if (dial->angle < -M_PI/2.)
+    dial->angle += 2*M_PI;
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Displaying a widget on the screen
-<p>
-There are several steps that are involved in displaying on the screen.
-After the widget is created with a call to <tt/WIDGETNAME_new()/,
-several more functions are needed:
+  if (dial->angle < -M_PI/6)
+    dial->angle = -M_PI/6;
 
-<itemize>
-<item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
-window for the widget if it has one.
-<item> <tt/WIDGETNAME_map()/ is invoked after the user calls
-<tt/gtk_widget_show()/. It is responsible for making sure the widget
-is actually drawn on the screen (<em/mapped/). For a container class,
-it must also make calls to <tt/map()/> functions of any child widgets.
-<item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
-is called for the widget or one of its ancestors. It makes the actual
-calls to the drawing functions to draw the widget on the screen. For
-container widgets, this function must make calls to
-<tt/gtk_widget_draw()/ for its child widgets.
-<item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
-widget. It makes the necessary calls to the drawing functions to draw
-the exposed portion on the screen. For container widgets, this
-function must generate expose events for its child widgets which don't
-have their own windows. (If they have their own windows, then X will
-generate the necessary expose events)
-</itemize>
+  if (dial->angle > 7.*M_PI/6.)
+    dial->angle = 7.*M_PI/6.;
 
-You might notice that the last two functions are quite similar - each
-is responsible for drawing the widget on the screen. In fact many
-types of widgets don't really care about the difference between the
-two. The default <tt/draw()/ function in the widget class simply
-generates a synthetic expose event for the redrawn area. However, some
-types of widgets can save work by distinguishing between the two
-functions. For instance, if a widget has multiple X windows, then
-since expose events identify the exposed window, it can redraw only
-the affected window, which is not possible for calls to <tt/draw()/.
+  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
 
-Container widgets, even if they don't care about the difference for
-themselves, can't simply use the default <tt/draw()/ function because
-their child widgets might care about the difference. However,
-it would be wasteful to duplicate the drawing code between the two
-functions. The convention is that such widgets have a function called
-<tt/WIDGETNAME_paint()/ that does the actual work of drawing the
-widget, that is then called by the <tt/draw()/ and <tt/expose()/
-functions.
+  if (dial->adjustment->value != old_value)
+    {
+      if (dial->policy == GTK_UPDATE_CONTINUOUS)
+       {
+         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+       }
+      else
+       {
+         gtk_widget_draw (GTK_WIDGET(dial), NULL);
 
-In our example approach, since the dial widget is not a container
-widget, and only has a single window, we can take the simplest
-approach and use the default <tt/draw()/ function and only implement
-an <tt/expose()/ function.
+         if (dial->policy == GTK_UPDATE_DELAYED)
+           {
+             if (dial->timer)
+               gtk_timeout_remove (dial->timer);
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The origins of the Dial Widget
-<p>
-Just as all land animals are just variants on the first amphibian that
-crawled up out of the mud, Gtk widgets tend to start off as variants
-of some other, previously written widget.  Thus, although this section
-is entilted ``Creating a Widget from Scratch'', the Dial widget really
-began with the source code for the Range widget. This was picked as a
-starting point because it would be nice if our Dial had the same
-interface as the Scale widgets which are just specialized descendents
-of the Range widget. So, though the source code is presented below in
-finished form, it should not be implied that it was written, <em>deus
-ex machina</em> in this fashion. Also, if you aren't yet familiar with
-how scale widgets work from the application writer's point of view, it
-would be a good idea to look them over before continuing.
+             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+                                            (GtkFunction) gtk_dial_timer,
+                                            (gpointer) dial);
+           }
+       }
+    }
+}
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The Basics
 <p>
-Quite a bit of our widget should look pretty familiar from the
-Tictactoe widget. First, we have a header file:
+Changes to the Adjustment by external means are communicated to our
+widget by the ``changed'' and ``value_changed'' signals. The handlers
+for these functions call <tt/gtk_dial_update()/ to validate the
+arguments, compute the new pointer angle, and redraw the widget (by
+calling <tt/gtk_widget_draw()/).
 
 <tscreen><verb>
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+static void
+gtk_dial_update (GtkDial *dial)
+{
+  gfloat new_value;
+  
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-#ifndef __GTK_DIAL_H__
-#define __GTK_DIAL_H__
+  new_value = dial->adjustment->value;
+  
+  if (new_value < dial->adjustment->lower)
+    new_value = dial->adjustment->lower;
 
-#include <gdk/gdk.h>
-#include <gtk/gtkadjustment.h>
-#include <gtk/gtkwidget.h>
+  if (new_value > dial->adjustment->upper)
+    new_value = dial->adjustment->upper;
+
+  if (new_value != dial->adjustment->value)
+    {
+      dial->adjustment->value = new_value;
+      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
 
+  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+    (dial->adjustment->upper - dial->adjustment->lower);
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+  gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}
 
+static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
+{
+  GtkDial *dial;
 
-#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
-#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
-#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
+  dial = GTK_DIAL (data);
 
-typedef struct _GtkDial        GtkDial;
-typedef struct _GtkDialClass   GtkDialClass;
+  if ((dial->old_value != adjustment->value) ||
+      (dial->old_lower != adjustment->lower) ||
+      (dial->old_upper != adjustment->upper))
+    {
+      gtk_dial_update (dial);
+
+      dial->old_value = adjustment->value;
+      dial->old_lower = adjustment->lower;
+      dial->old_upper = adjustment->upper;
+    }
+}
 
-struct _GtkDial
+static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
 {
-  GtkWidget widget;
+  GtkDial *dial;
 
-  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
-  guint policy : 2;
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-  /* Button currently pressed or 0 if none */
-  guint8 button;
+  dial = GTK_DIAL (data);
 
-  /* Dimensions of dial components */
-  gint radius;
-  gint pointer_width;
+  if (dial->old_value != adjustment->value)
+    {
+      gtk_dial_update (dial);
 
-  /* ID of update timer, or 0 if none */
-  guint32 timer;
+      dial->old_value = adjustment->value;
+    }
+}
+</verb></tscreen>
 
-  /* Current angle */
-  gfloat angle;
+<!-- ----------------------------------------------------------------- -->
+<sect2> Possible Enhancements
+<p>
 
-  /* Old values from adjustment stored so we know when something changes */
-  gfloat old_value;
-  gfloat old_lower;
-  gfloat old_upper;
+The Dial widget as we've described it so far runs about 670 lines of
+code. Although that might sound like a fair bit, we've really
+accomplished quite a bit with that much code, especially since much of
+that length is headers and boilerplate. However, there are quite a few
+more enhancements that could be made to this widget:
 
-  /* The adjustment object that stores the data for this dial */
-  GtkAdjustment *adjustment;
-};
+<itemize>
+<item> If you try this widget out, you'll find that there is some
+flashing as the pointer is dragged around. This is because the entire
+widget is erased every time the pointer is moved before being
+redrawn. Often, the best way to handle this problem is to draw to an
+offscreen pixmap, then copy the final results onto the screen in one
+step. (The ProgressBar widget draws itself in this fashion.)
 
-struct _GtkDialClass
-{
-  GtkWidgetClass parent_class;
-};
+<item> The user should be able to use the up and down arrow keys to
+increase and decrease the value.
 
+<item> It would be nice if the widget had buttons to increase and
+decrease the value in small or large steps. Although it would be
+possible to use embedded Button widgets for this, we would also like
+the buttons to auto-repeat when held down, as the arrows on a
+scrollbar do. Most of the code to implement this type of behavior can
+be found in the GtkRange widget.
 
-GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
-guint          gtk_dial_get_type               (void);
-GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
-void           gtk_dial_set_update_policy      (GtkDial      *dial,
-                                               GtkUpdateType  policy);
+<item> The Dial widget could be made into a container widget with a
+single child widget positioned at the bottom between the buttons
+mentioned above. The user could then add their choice of a label or
+entry widget to display the current value of the dial.
 
-void           gtk_dial_set_adjustment         (GtkDial      *dial,
-                                               GtkAdjustment *adjustment);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+</itemize>
 
+<!-- ----------------------------------------------------------------- -->
+<sect1> Learning More
 
-#endif /* __GTK_DIAL_H__ */
-</verb></tscreen>
+<p>
+Only a small part of the many details involved in creating widgets
+could be described above. If you want to write your own widgets, the
+best source of examples is the GTK source itself. Ask yourself some
+questions about the widget you want to write: is it a Container
+widget? does it have its own window? is it a modification of an
+existing widget? Then find a similar widget, and start making changes.
+Good luck!
 
-Since there is quite a bit more going on in this widget, than the last
-one, we have more fields in the data structure, but otherwise things
-are pretty similar.
+<!-- ***************************************************************** -->
+<sect>Scribble, A Simple Example Drawing Program
+<!-- ***************************************************************** -->
 
-Next, after including header files, and declaring a few constants,
-we have some functions to provide information about the widget
-and initialize it:
+<!-- ----------------------------------------------------------------- -->
+<sect1> Overview
 
-<tscreen><verb>
-#include <math.h>
-#include <stdio.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
+<p>
+In this section, we will build a simple drawing program. In the
+process, we will examine how to handle mouse events, how to draw in a
+window, and how to do drawing better by using a backing pixmap. After
+creating the simple drawing program, we will extend it by adding
+support for XInput devices, such as drawing tablets. GTK provides
+support routines which makes getting extended information, such as
+pressure and tilt, from such devices quite easy.
 
-#include "gtkdial.h"
+<!-- ----------------------------------------------------------------- -->
+<sect1> Event Handling
 
-#define SCROLL_DELAY_LENGTH  300
-#define DIAL_DEFAULT_SIZE 100
+<p>
+The GTK signals we have already discussed are for high-level actions,
+such as a menu item being selected. However, sometimes it is useful to
+learn about lower-level occurrences, such as the mouse being moved, or
+a key being pressed. There are also GTK signals corresponding to these
+low-level <em>events</em>. The handlers for these signals have an
+extra parameter which is a pointer to a structure containing
+information about the event. For instance, motion events handlers are
+passed a pointer to a GdkEventMotion structure which looks (in part)
+like:
 
-/* Forward declararations */
+<tscreen><verb>
+struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  ...
+  guint state;
+  ...
+};
+</verb></tscreen>
 
-[ omitted to save space ]
+<tt/type/ will be set to the event type, in this case
+<tt/GDK_MOTION_NOTIFY/, window is the window in which the event
+occured. <tt/x/ and <tt/y/ give the coordinates of the event,
+and <tt/state/ specifies the modifier state when the event
+occurred (that is, it specifies which modifier keys and mouse buttons
+were pressed.) It is the bitwise OR of some of the following:
 
-/* Local data */
+<tscreen><verb>
+GDK_SHIFT_MASK  
+GDK_LOCK_MASK   
+GDK_CONTROL_MASK
+GDK_MOD1_MASK   
+GDK_MOD2_MASK   
+GDK_MOD3_MASK   
+GDK_MOD4_MASK   
+GDK_MOD5_MASK   
+GDK_BUTTON1_MASK
+GDK_BUTTON2_MASK
+GDK_BUTTON3_MASK
+GDK_BUTTON4_MASK
+GDK_BUTTON5_MASK
+</verb></tscreen>
 
-static GtkWidgetClass *parent_class = NULL;
+<p>
+As for other signals, to determine what happens when an event occurs
+we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
+know which events we want to be notified about. To do this, we call
+the function:
 
-guint
-gtk_dial_get_type ()
-{
-  static guint dial_type = 0;
+<tscreen><verb>
+void gtk_widget_set_events (GtkWidget *widget,
+                            gint      events);
+</verb></tscreen>
 
-  if (!dial_type)
-    {
-      GtkTypeInfo dial_info =
-      {
-       "GtkDial",
-       sizeof (GtkDial),
-       sizeof (GtkDialClass),
-       (GtkClassInitFunc) gtk_dial_class_init,
-       (GtkObjectInitFunc) gtk_dial_init,
-       (GtkArgSetFunc) NULL,
-        (GtkArgGetFunc) NULL,
-      };
+The second field specifies the events we are interested in. It
+is the bitwise OR of constants that specify different types
+of events. For future reference the event types are:
 
-      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
-    }
+<tscreen><verb>
+GDK_EXPOSURE_MASK
+GDK_POINTER_MOTION_MASK
+GDK_POINTER_MOTION_HINT_MASK
+GDK_BUTTON_MOTION_MASK     
+GDK_BUTTON1_MOTION_MASK    
+GDK_BUTTON2_MOTION_MASK    
+GDK_BUTTON3_MOTION_MASK    
+GDK_BUTTON_PRESS_MASK      
+GDK_BUTTON_RELEASE_MASK    
+GDK_KEY_PRESS_MASK         
+GDK_KEY_RELEASE_MASK       
+GDK_ENTER_NOTIFY_MASK      
+GDK_LEAVE_NOTIFY_MASK      
+GDK_FOCUS_CHANGE_MASK      
+GDK_STRUCTURE_MASK         
+GDK_PROPERTY_CHANGE_MASK   
+GDK_PROXIMITY_IN_MASK      
+GDK_PROXIMITY_OUT_MASK     
+</verb></tscreen>
 
-  return dial_type;
-}
+There are a few subtle points that have to be observed when calling
+<tt/gtk_widget_set_events()/. First, it must be called before the X window
+for a GTK widget is created. In practical terms, this means you
+should call it immediately after creating the widget. Second, the
+widget must have an associated X window. For efficiency, many widget
+types do not have their own window, but draw in their parent's window.
+These widgets are:
 
-static void
-gtk_dial_class_init (GtkDialClass *class)
-{
-  GtkObjectClass *object_class;
-  GtkWidgetClass *widget_class;
+<tscreen><verb>
+GtkAlignment
+GtkArrow
+GtkBin
+GtkBox
+GtkImage
+GtkItem
+GtkLabel
+GtkPixmap
+GtkScrolledWindow
+GtkSeparator
+GtkTable
+GtkAspectFrame
+GtkFrame
+GtkVBox
+GtkHBox
+GtkVSeparator
+GtkHSeparator
+</verb></tscreen>
 
-  object_class = (GtkObjectClass*) class;
-  widget_class = (GtkWidgetClass*) class;
+To capture events for these widgets, you need to use an EventBox 
+widget. See the section on   
+<ref id="sec_The_EventBox_Widget" name="The EventBox Widget"> for
+details.
 
-  parent_class = gtk_type_class (gtk_widget_get_type ());
+<p>
+For our drawing program, we want to know when the mouse button is
+pressed and when the mouse is moved, so we specify
+<tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
+want to know when we need to redraw our window, so we specify
+<tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
+Configure event when our window size changes, we don't have to specify
+the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
+automatically specified for all windows.
 
-  object_class->destroy = gtk_dial_destroy;
+<p>
+It turns out, however, that there is a problem with just specifying
+<tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
+motion event to the event queue every time the user moves the mouse.
+Imagine that it takes us 0.1 seconds to handle a motion event, but the
+X server queues a new motion event every 0.05 seconds. We will soon
+get way behind the users drawing. If the user draws for 5 seconds,
+it will take us another 5 seconds to catch up after they release 
+the mouse button! What we would like is to only get one motion
+event for each event we process. The way to do this is to 
+specify <tt/GDK_POINTER_MOTION_HINT_MASK/. 
 
-  widget_class->realize = gtk_dial_realize;
-  widget_class->expose_event = gtk_dial_expose;
-  widget_class->size_request = gtk_dial_size_request;
-  widget_class->size_allocate = gtk_dial_size_allocate;
-  widget_class->button_press_event = gtk_dial_button_press;
-  widget_class->button_release_event = gtk_dial_button_release;
-  widget_class->motion_notify_event = gtk_dial_motion_notify;
-}
+<p>
+When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
+us a motion event the first time the pointer moves after entering
+our window, or after a button press or release event. Subsequent 
+motion events will be suppressed until we explicitely ask for
+the position of the pointer using the function:
 
-static void
-gtk_dial_init (GtkDial *dial)
-{
-  dial->button = 0;
-  dial->policy = GTK_UPDATE_CONTINUOUS;
-  dial->timer = 0;
-  dial->radius = 0;
-  dial->pointer_width = 0;
-  dial->angle = 0.0;
-  dial->old_value = 0.0;
-  dial->old_lower = 0.0;
-  dial->old_upper = 0.0;
-  dial->adjustment = NULL;
-}
+<tscreen><verb>
+GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y,
+                                         GdkModifierType *mask);
+</verb></tscreen>
 
-GtkWidget*
-gtk_dial_new (GtkAdjustment *adjustment)
-{
-  GtkDial *dial;
+(There is another function, <tt>gtk_widget_get_pointer()</tt> which
+has a simpler interface, but turns out not to be very useful, since
+it only retrieves the position of the mouse, not whether the buttons
+are pressed.)
 
-  dial = gtk_type_new (gtk_dial_get_type ());
+<p>
+The code to set the events for our window then looks like:
 
-  if (!adjustment)
-    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+<tscreen><verb>
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                     (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                     (GtkSignalFunc) configure_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                     (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                     (GtkSignalFunc) button_press_event, NULL);
 
-  gtk_dial_set_adjustment (dial, adjustment);
+  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                        | GDK_LEAVE_NOTIFY_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_POINTER_MOTION_HINT_MASK);
+</verb></tscreen>
 
-  return GTK_WIDGET (dial);
-}
+We'll save the "expose_event" and "configure_event" handlers for
+later. The "motion_notify_event" and "button_press_event" handlers
+pretty simple:
 
-static void
-gtk_dial_destroy (GtkObject *object)
+<tscreen><verb>
+static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
-  GtkDial *dial;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (GTK_IS_DIAL (object));
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+      draw_brush (widget, event->x, event->y);
 
-  dial = GTK_DIAL (object);
+  return TRUE;
+}
 
-  if (dial->adjustment)
-    gtk_object_unref (GTK_OBJECT (dial->adjustment));
+static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+  int x, y;
+  GdkModifierType state;
 
-  if (GTK_OBJECT_CLASS (parent_class)->destroy)
-    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+  if (event->is_hint)
+    gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, x, y);
+  
+  return TRUE;
 }
 </verb></tscreen>
 
-Note that this <tt/init()/ function does less than for the Tictactoe
-widget, since this is not a composite widget, and the <tt/new()/
-function does more, since it now has an argument. Also, note that when
-we store a pointer to the Adjustment object, we increment its
-reference count, (and correspondingly decrement when we no longer use
-it) so that GTK can keep track of when it can be safely destroyed.
+<!-- ----------------------------------------------------------------- -->
+<sect1> The DrawingArea Widget, And Drawing
 
 <p>
-Also, there are a few function to manipulate the widget's options:
+We know turn to the process of drawing on the screen. The 
+widget we use for this is the DrawingArea widget. A drawing area
+widget is essentially an X window and nothing more. It is a blank
+canvas in which we can draw whatever we like. A drawing area
+is created using the call:
 
 <tscreen><verb>
-GtkAdjustment*
-gtk_dial_get_adjustment (GtkDial *dial)
-{
-  g_return_val_if_fail (dial != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
-
-  return dial->adjustment;
-}
-
-void
-gtk_dial_set_update_policy (GtkDial      *dial,
-                            GtkUpdateType  policy)
-{
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
+GtkWidget* gtk_drawing_area_new        (void);
+</verb></tscreen>
 
-  dial->policy = policy;
-}
+A default size for the widget can be specified by calling:
 
-void
-gtk_dial_set_adjustment (GtkDial      *dial,
-                         GtkAdjustment *adjustment)
-{
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
+<tscreen><verb>
+void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
+                                       gint                 width,
+                                       gint                 height);
+</verb></tscreen>
 
-  if (dial->adjustment)
-    {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
-      gtk_object_unref (GTK_OBJECT (dial->adjustment));
-    }
+This default size can be overriden, as is true for all widgets,
+by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
+be overridden if the user manually resizes the the window containing
+the drawing area.
 
-  dial->adjustment = adjustment;
-  gtk_object_ref (GTK_OBJECT (dial->adjustment));
+<p>
+It should be noted that when we create a DrawingArea widget, we are,
+<em>completely</em> responsible for drawing the contents. If our
+window is obscured then uncovered, we get an exposure event and must
+redraw what was previously hidden.
 
-  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
-                     (GtkSignalFunc) gtk_dial_adjustment_changed,
-                     (gpointer) dial);
-  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
-                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
-                     (gpointer) dial);
+<p>
+Having to remember everything that was drawn on the screen so we
+can properly redraw it can, to say the least, be a nuisance. In
+addition, it can be visually distracting if portions of the
+window are cleared, then redrawn step by step. The solution to
+this problem is to use an offscreen <em>backing pixmap</em>.
+Instead of drawing directly to the screen, we draw to an image
+stored in server memory but not displayed, then when the image
+changes or new portions of the image are displayed, we copy the
+relevant portions onto the screen.
 
-  dial->old_value = adjustment->value;
-  dial->old_lower = adjustment->lower;
-  dial->old_upper = adjustment->upper;
+<p>
+To create an offscreen pixmap, we call the function:
 
-  gtk_dial_update (dial);
-}
+<tscreen><verb>
+GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
+                                        gint        width,
+                                        gint        height,
+                                        gint        depth);
 </verb></tscreen>
 
-<sect2> <tt/gtk_dial_realize()/
+The <tt>window</tt> parameter specifies a GDK window that this pixmap
+takes some of its properties from. <tt>width</tt> and <tt>height</tt>
+specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
+depth</em>, that is the number of bits per pixel, for the new window.
+If the depth is specified as <tt>-1</tt>, it will match the depth
+of <tt>window</tt>.
 
 <p>
-Now we come to some new types of functions. First, we have a function
-that does the work of creating the X window. Notice that a mask is
-passed to the function <tt/gdk_window_new()/ which specifies which fields of
-the GdkWindowAttr structure actually have data in them (the remaining
-fields wll be given default values). Also worth noting is the way the
-event mask of the widget is created. We call
-<tt/gtk_widget_get_events()/ to retrieve the event mask that the user
-has specified for this widget (with <tt/gtk_widget_set_events()/, and
-add the events that we are interested in ourselves.
+We create the pixmap in our "configure_event" handler. This event
+is generated whenever the window changes size, including when it
+is originally created.
+
+<tscreen><verb>
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;
+
+/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+  if (pixmap)
+    gdk_pixmap_unref(pixmap);
+
+  pixmap = gdk_pixmap_new(widget->window,
+                         widget->allocation.width,
+                         widget->allocation.height,
+                         -1);
+  gdk_draw_rectangle (pixmap,
+                     widget->style->white_gc,
+                     TRUE,
+                     0, 0,
+                     widget->allocation.width,
+                     widget->allocation.height);
+
+  return TRUE;
+}
+</verb></tscreen>
+
+The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
+initially to white. We'll say more about that in a moment.
 
 <p>
-After creating the window, we set its style and background, and put a
-pointer to the widget in the user data field of the GdkWindow. This
-last step allows GTK to dispatch events for this window to the correct
-widget.
+Our exposure event handler then simply copies the relevant portion
+of the pixmap onto the screen (we determine the area we need
+to redraw by using the event->area field of the exposure event):
 
 <tscreen><verb>
-static void
-gtk_dial_realize (GtkWidget *widget)
+/* Redraw the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
 {
-  GtkDial *dial;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
+  gdk_draw_pixmap(widget->window,
+                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                 pixmap,
+                 event->area.x, event->area.y,
+                 event->area.x, event->area.y,
+                 event->area.width, event->area.height);
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_DIAL (widget));
+  return FALSE;
+}
+</verb></tscreen>
 
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-  dial = GTK_DIAL (widget);
+We've now seen how to keep the screen up to date with our pixmap, but
+how do we actually draw interesting stuff on our pixmap?  There are a
+large number of calls in GTK's GDK library for drawing on
+<em>drawables</em>. A drawable is simply something that can be drawn
+upon. It can be a window, a pixmap, or a bitmap (a black and white
+image).  We've already seen two such calls above,
+<tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
+complete list is:
 
-  attributes.x = widget->allocation.x;
-  attributes.y = widget->allocation.y;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->allocation.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.event_mask = gtk_widget_get_events (widget) | 
-    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
-    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
-    GDK_POINTER_MOTION_HINT_MASK;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
+<tscreen><verb>
+gdk_draw_line ()
+gdk_draw_rectangle ()
+gdk_draw_arc ()
+gdk_draw_polygon ()
+gdk_draw_string ()
+gdk_draw_text ()
+gdk_draw_pixmap ()
+gdk_draw_bitmap ()
+gdk_draw_image ()
+gdk_draw_points ()
+gdk_draw_segments ()
+</verb></tscreen>
 
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
+See the reference documentation or the header file
+<tt>&lt;gdk/gdk.h&gt;</tt> for further details on these functions.
+These functions all share the same first two arguments. The first
+argument is the drawable to draw upon, the second argument is a
+<em>graphics context</em> (GC). 
 
-  widget->style = gtk_style_attach (widget->style, widget->window);
+<p>
+A graphics context encapsulates information about things such as
+foreground and background color and line width. GDK has a full set of
+functions for creating and modifying graphics contexts, but to keep
+things simple we'll just use predefined graphics contexts. Each widget
+has an associated style. (Which can be modified in a gtkrc file, see
+the section GTK's rc file.) This, among other things, stores a number
+of graphics contexts. Some examples of accessing these graphics
+contexts are:
 
-  gdk_window_set_user_data (widget->window, widget);
+<tscreen><verb>
+widget->style->white_gc
+widget->style->black_gc
+widget->style->fg_gc[GTK_STATE_NORMAL]
+widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
+</verb></tscreen>
 
-  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
-}
+The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
+<tt>light_gc</tt> are indexed by a parameter of type
+<tt>GtkStateType</tt> which can take on the values:
+
+<tscreen><verb>
+GTK_STATE_NORMAL,
+GTK_STATE_ACTIVE,
+GTK_STATE_PRELIGHT,
+GTK_STATE_SELECTED,
+GTK_STATE_INSENSITIVE
 </verb></tscreen>
 
-<sect2> Size negotiation
+For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
+color is white and the default background color, dark blue.
 
 <p>
-Before the first time that the window containing a widget is
-displayed, and whenever the layout of the window changes, GTK asks
-each child widget for its desired size. This request is handled by the
-function, <tt/gtk_dial_size_request()/. Since our widget isn't a
-container widget, and has no real constraints on its size, we just
-return a reasonable default value.
+Our function <tt>draw_brush()</tt>, which does the actual drawing
+on the screen, is then:
 
 <tscreen><verb>
-static void 
-gtk_dial_size_request (GtkWidget      *widget,
-                      GtkRequisition *requisition)
+/* Draw a rectangle on the screen */
+static void
+draw_brush (GtkWidget *widget, gdouble x, gdouble y)
 {
-  requisition->width = DIAL_DEFAULT_SIZE;
-  requisition->height = DIAL_DEFAULT_SIZE;
+  GdkRectangle update_rect;
+
+  update_rect.x = x - 5;
+  update_rect.y = y - 5;
+  update_rect.width = 10;
+  update_rect.height = 10;
+  gdk_draw_rectangle (pixmap,
+                     widget->style->black_gc,
+                     TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
 }
 </verb></tscreen>
 
-<p>
-After all the widgets have requested an ideal size, the layout of the
-window is computed and each child widget is notified of its actual
-size. Usually, this will at least as large as the requested size, but
-if for instance, the user has resized the window, it may occasionally
-be smaller than the requested size. The size notification is handled
-by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
-computing the sizes of some component pieces for future use, this
-routine also does the grunt work of moving the widgets X window into
-the new position and size.
+After we draw the rectangle representing the brush onto the pixmap,
+we call the function:
 
 <tscreen><verb>
-static void
-gtk_dial_size_allocate (GtkWidget     *widget,
-                       GtkAllocation *allocation)
-{
-  GtkDial *dial;
+void       gtk_widget_draw                (GtkWidget           *widget,
+                                          GdkRectangle        *area);
+</verb></tscreen>
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_DIAL (widget));
-  g_return_if_fail (allocation != NULL);
+which notifies X that the area given by the <tt>area</tt> parameter
+needs to be updated. X will eventually generate an expose event
+(possibly combining the areas passed in several calls to
+<tt>gtk_widget_draw()</tt>) which will cause our expose event handler
+to copy the relevant portions to the screen.
 
-  widget->allocation = *allocation;
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      dial = GTK_DIAL (widget);
+<p>
+We have now covered the entire drawing program except for a few
+mundane details like creating the main window. The complete
+source code is available from the location from which you got
+this tutorial, or from:
 
-      gdk_window_move_resize (widget->window,
-                             allocation->x, allocation->y,
-                             allocation->width, allocation->height);
+<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
+name="http://www.gtk.org/~otaylor/gtk/tutorial/">
 
-      dial->radius = MAX(allocation->width,allocation->height) * 0.45;
-      dial->pointer_width = dial->radius / 5;
-    }
-}
-</verb></tscreen>.
 
 <!-- ----------------------------------------------------------------- -->
-<sect2> <tt/gtk_dial_expose()/
+<sect1> Adding XInput support
 
 <p>
-As mentioned above, all the drawing of this widget is done in the
-handler for expose events. There's not much to remark on here except
-the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
-three dimensional shading according to the colors stored in the
-widget's style.
-
-<tscreen><verb>
-static gint
-gtk_dial_expose (GtkWidget      *widget,
-                GdkEventExpose *event)
-{
-  GtkDial *dial;
-  GdkPoint points[3];
-  gdouble s,c;
-  gdouble theta;
-  gint xc, yc;
-  gint tick_length;
-  gint i;
 
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  if (event->count > 0)
-    return FALSE;
-  
-  dial = GTK_DIAL (widget);
+It is now possible to buy quite inexpensive input devices such 
+as drawing tablets, which allow drawing with a much greater
+ease of artistic expression than does a mouse. The simplest way
+to use such devices is simply as a replacement for the mouse,
+but that misses out many of the advantages of these devices,
+such as:
 
-  gdk_window_clear_area (widget->window,
-                        0, 0,
-                        widget->allocation.width,
-                        widget->allocation.height);
+<itemize>
+<item> Pressure sensitivity
+<item> Tilt reporting
+<item> Sub-pixel positioning
+<item> Multiple inputs (for example, a stylus with a point and eraser)
+</itemize>
 
-  xc = widget->allocation.width/2;
-  yc = widget->allocation.height/2;
+For information about the XInput extension, see the <htmlurl
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
+name="XInput-HOWTO">.
 
-  /* Draw ticks */
+<p>
+If we examine the full definition of, for example, the GdkEventMotion
+structure, we see that it has fields to support extended device
+information.
 
-  for (i=0; i<25; i++)
-    {
-      theta = (i*M_PI/18. - M_PI/6.);
-      s = sin(theta);
-      c = cos(theta);
+<tscreen><verb>
+struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  gint16 is_hint;
+  GdkInputSource source;
+  guint32 deviceid;
+};
+</verb></tscreen>
 
-      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
-      
-      gdk_draw_line (widget->window,
-                    widget->style->fg_gc[widget->state],
-                    xc + c*(dial->radius - tick_length),
-                    yc - s*(dial->radius - tick_length),
-                    xc + c*dial->radius,
-                    yc - s*dial->radius);
-    }
+<tt/pressure/ gives the pressure as a floating point number between
+0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between 
+-1 and 1, corresponding to the degree of tilt in each direction.
+<tt/source/ and <tt/deviceid/ specify the device for which the
+event occurred in two different ways. <tt/source/ gives some simple
+information about the type of device. It can take the enumeration
+values.
 
-  /* Draw pointer */
+<tscreen><verb>
+GDK_SOURCE_MOUSE
+GDK_SOURCE_PEN
+GDK_SOURCE_ERASER
+GDK_SOURCE_CURSOR
+</verb></tscreen>
 
-  s = sin(dial->angle);
-  c = cos(dial->angle);
+<tt/deviceid/ specifies a unique numeric ID for the device. This can
+be used to find out further information about the device using the
+<tt/gdk_input_list_devices()/ call (see below). The special value
+<tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
+the mouse.)
 
+<sect2> Enabling extended device information
 
-  points[0].x = xc + s*dial->pointer_width/2;
-  points[0].y = yc + c*dial->pointer_width/2;
-  points[1].x = xc + c*dial->radius;
-  points[1].y = yc - s*dial->radius;
-  points[2].x = xc - s*dial->pointer_width/2;
-  points[2].y = yc - c*dial->pointer_width/2;
+<p>
+To let GTK know about our interest in the extended device information,
+we merely have to add a single line to our program:
 
-  gtk_draw_polygon (widget->style,
-                   widget->window,
-                   GTK_STATE_NORMAL,
-                   GTK_SHADOW_OUT,
-                   points, 3,
-                   TRUE);
-  
-  return FALSE;
-}
+<tscreen><verb>
+gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
 </verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Event handling
-
-<p>
-
-The rest of the widget's code handles various types of events, and
-isn't too different from what would be found in many GTK
-applications. Two types of events can occur - either the user can
-click on the widget with the mouse and drag to move the pointer, or
-the value of the Adjustment object can change due to some external
-circumstance. 
+By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
+we are interested in extension events, but only if we don't have
+to draw our own cursor. See the section <ref
+id="sec_Further_Sophistications" name="Further Sophistications"> below
+for more information about drawing the cursor. We could also 
+give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing 
+to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
+back to the default condition.
 
 <p>
-When the user clicks on the widget, we check to see if the click was
-appropriately near the pointer, and if so, store then button that the
-user clicked with in the <tt/button/ field of the widget
-structure, and grab all mouse events with a call to
-<tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
-value of the control to be recomputed (by the function
-<tt/gtk_dial_update_mouse/). Depending on the policy that has been
-set, "value_changed" events are either generated instantly
-(<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
-<tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
-button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
+This is not completely the end of the story however. By default,
+no extension devices are enabled. We need a mechanism to allow
+users to enable and configure their extension devices. GTK provides
+the InputDialog widget to automate this process. The following
+procedure manages an InputDialog widget. It creates the dialog if
+it isn't present, and raises it to the top otherwise.
 
 <tscreen><verb>
-static gint
-gtk_dial_button_press (GtkWidget      *widget,
-                      GdkEventButton *event)
+void
+input_dialog_destroy (GtkWidget *w, gpointer data)
 {
-  GtkDial *dial;
-  gint dx, dy;
-  double s, c;
-  double d_parallel;
-  double d_perpendicular;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  *((GtkWidget **)data) = NULL;
+}
 
-  dial = GTK_DIAL (widget);
+void
+create_input_dialog ()
+{
+  static GtkWidget *inputd = NULL;
 
-  /* Determine if button press was within pointer region - we 
-     do this by computing the parallel and perpendicular distance of
-     the point where the mouse was pressed from the line passing through
-     the pointer */
-  
-  dx = event->x - widget->allocation.width / 2;
-  dy = widget->allocation.height / 2 - event->y;
-  
-  s = sin(dial->angle);
-  c = cos(dial->angle);
-  
-  d_parallel = s*dy + c*dx;
-  d_perpendicular = fabs(s*dx - c*dy);
-  
-  if (!dial->button &&
-      (d_perpendicular < dial->pointer_width/2) &&
-      (d_parallel > - dial->pointer_width))
+  if (!inputd)
     {
-      gtk_grab_add (widget);
+      inputd = gtk_input_dialog_new();
 
-      dial->button = event->button;
+      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
+                         (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
+      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
+                                "clicked",
+                                (GtkSignalFunc)gtk_widget_hide,
+                                GTK_OBJECT(inputd));
+      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
 
-      gtk_dial_update_mouse (dial, event->x, event->y);
+      gtk_widget_show (inputd);
+    }
+  else
+    {
+      if (!GTK_WIDGET_MAPPED(inputd))
+       gtk_widget_show(inputd);
+      else
+       gdk_window_raise(inputd->window);
     }
-
-  return FALSE;
 }
+</verb></tscreen>
 
-static gint
-gtk_dial_button_release (GtkWidget      *widget,
-                         GdkEventButton *event)
-{
-  GtkDial *dial;
+(You might want to take note of the way we handle this dialog.  By
+connecting to the "destroy" signal, we make sure that we don't keep a
+pointer to dialog around after it is destroyed - that could lead to a
+segfault.)
 
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+<p>
+The InputDialog has two buttons "Close" and "Save", which by default
+have no actions assigned to them. In the above function we make
+"Close" hide the dialog, hide the "Save" button, since we don't
+implement saving of XInput options in this program.
 
-  dial = GTK_DIAL (widget);
+<sect2> Using extended device information
 
-  if (dial->button == event->button)
-    {
-      gtk_grab_remove (widget);
+<p>
+Once we've enabled the device, we can just use the extended 
+device information in the extra fields of the event structures.
+In fact, it is always safe to use this information since these
+fields will have reasonable default values even when extended
+events are not enabled.
 
-      dial->button = 0;
+<p>
+Once change we do have to make is to call
+<tt/gdk_input_window_get_pointer()/ instead of
+<tt/gdk_window_get_pointer/. This is necessary because
+<tt/gdk_window_get_pointer/ doesn't return the extended device
+information.
 
-      if (dial->policy == GTK_UPDATE_DELAYED)
-       gtk_timeout_remove (dial->timer);
-      
-      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
-         (dial->old_value != dial->adjustment->value))
-       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
-    }
+<tscreen><verb>
+void gdk_input_window_get_pointer     (GdkWindow       *window,
+                                      guint32         deviceid,
+                                      gdouble         *x,
+                                      gdouble         *y,
+                                      gdouble         *pressure,
+                                      gdouble         *xtilt,
+                                      gdouble         *ytilt,
+                                      GdkModifierType *mask);
+</verb></tscreen>
 
-  return FALSE;
-}
+When calling this function, we need to specify the device ID as
+well as the window. Usually, we'll get the device ID from the
+<tt/deviceid/ field of an event structure. Again, this function
+will return reasonable values when extension events are not
+enabled. (In this case, <tt/event->deviceid/ will have the value
+<tt/GDK_CORE_POINTER/).
 
+So the basic structure of our button-press and motion event handlers,
+doesn't change much - we just need to add code to deal with the
+extended information.
+
+<tscreen><verb>
 static gint
-gtk_dial_motion_notify (GtkWidget      *widget,
-                        GdkEventMotion *event)
+button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
-  GtkDial *dial;
-  GdkModifierType mods;
-  gint x, y, mask;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  dial = GTK_DIAL (widget);
-
-  if (dial->button != 0)
-    {
-      x = event->x;
-      y = event->y;
-
-      if (event->is_hint || (event->window != widget->window))
-       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
-
-      switch (dial->button)
-       {
-       case 1:
-         mask = GDK_BUTTON1_MASK;
-         break;
-       case 2:
-         mask = GDK_BUTTON2_MASK;
-         break;
-       case 3:
-         mask = GDK_BUTTON3_MASK;
-         break;
-       default:
-         mask = 0;
-         break;
-       }
-
-      if (mods & mask)
-       gtk_dial_update_mouse (dial, x,y);
-    }
+  print_button_press (event->deviceid);
+  
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, event->x, event->y, event->pressure);
 
-  return FALSE;
+  return TRUE;
 }
 
 static gint
-gtk_dial_timer (GtkDial *dial)
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
 {
-  g_return_val_if_fail (dial != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
-
-  if (dial->policy == GTK_UPDATE_DELAYED)
-    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+  gdouble x, y;
+  gdouble pressure;
+  GdkModifierType state;
 
-  return FALSE;
+  if (event->is_hint)
+    gdk_input_window_get_pointer (event->window, event->deviceid,
+                                 &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      pressure = event->pressure;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, x, y, pressure);
+  
+  return TRUE;
 }
+</verb></tscreen>
+
+We also need to do something with the new information. Our new
+<tt/draw_brush()/ function draws with a different color for
+each <tt/event->source/ and changes the brush size depending
+on the pressure.
 
+<tscreen><verb>
+/* Draw a rectangle on the screen, size depending on pressure,
+   and color on the type of device */
 static void
-gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+draw_brush (GtkWidget *widget, GdkInputSource source,
+           gdouble x, gdouble y, gdouble pressure)
 {
-  gint xc, yc;
-  gfloat old_value;
-
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
-
-  xc = GTK_WIDGET(dial)->allocation.width / 2;
-  yc = GTK_WIDGET(dial)->allocation.height / 2;
-
-  old_value = dial->adjustment->value;
-  dial->angle = atan2(yc-y, x-xc);
-
-  if (dial->angle < -M_PI/2.)
-    dial->angle += 2*M_PI;
-
-  if (dial->angle < -M_PI/6)
-    dial->angle = -M_PI/6;
-
-  if (dial->angle > 7.*M_PI/6.)
-    dial->angle = 7.*M_PI/6.;
-
-  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
-    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
+  GdkGC *gc;
+  GdkRectangle update_rect;
 
-  if (dial->adjustment->value != old_value)
+  switch (source)
     {
-      if (dial->policy == GTK_UPDATE_CONTINUOUS)
-       {
-         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
-       }
-      else
-       {
-         gtk_widget_draw (GTK_WIDGET(dial), NULL);
-
-         if (dial->policy == GTK_UPDATE_DELAYED)
-           {
-             if (dial->timer)
-               gtk_timeout_remove (dial->timer);
-
-             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
-                                            (GtkFunction) gtk_dial_timer,
-                                            (gpointer) dial);
-           }
-       }
+    case GDK_SOURCE_MOUSE:
+      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
+      break;
+    case GDK_SOURCE_PEN:
+      gc = widget->style->black_gc;
+      break;
+    case GDK_SOURCE_ERASER:
+      gc = widget->style->white_gc;
+      break;
+    default:
+      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
     }
+
+  update_rect.x = x - 10 * pressure;
+  update_rect.y = y - 10 * pressure;
+  update_rect.width = 20 * pressure;
+  update_rect.height = 20 * pressure;
+  gdk_draw_rectangle (pixmap, gc, TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
 }
 </verb></tscreen>
 
+<sect2> Finding out more about a device
+
 <p>
-Changes to the Adjustment by external means are communicated to our
-widget by the ``changed'' and ``value_changed'' signals. The handlers
-for these functions call <tt/gtk_dial_update()/ to validate the
-arguments, compute the new pointer angle, and redraw the widget (by
-calling <tt/gtk_widget_draw()/).
+As an example of how to find out more about a device, our program
+will print the name of the device that generates each button
+press. To find out the name of a device, we call the function:
 
 <tscreen><verb>
-static void
-gtk_dial_update (GtkDial *dial)
-{
-  gfloat new_value;
-  
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
-
-  new_value = dial->adjustment->value;
-  
-  if (new_value < dial->adjustment->lower)
-    new_value = dial->adjustment->lower;
+GList *gdk_input_list_devices               (void);
+</verb></tscreen>
 
-  if (new_value > dial->adjustment->upper)
-    new_value = dial->adjustment->upper;
+which returns a GList (a linked list type from the glib library)
+of GdkDeviceInfo structures. The GdkDeviceInfo strucure is defined
+as:
 
-  if (new_value != dial->adjustment->value)
-    {
-      dial->adjustment->value = new_value;
-      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
-    }
+<tscreen><verb>
+struct _GdkDeviceInfo
+{
+  guint32 deviceid;
+  gchar *name;
+  GdkInputSource source;
+  GdkInputMode mode;
+  gint has_cursor;
+  gint num_axes;
+  GdkAxisUse *axes;
+  gint num_keys;
+  GdkDeviceKey *keys;
+};
+</verb></tscreen>
 
-  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
-    (dial->adjustment->upper - dial->adjustment->lower);
+Most of these fields are configuration information that you
+can ignore unless you are implemented XInput configuration
+saving. The we are interested in here is <tt/name/ which is
+simply the name that X assigns to the device. The other field
+that isn't configuration information is <tt/has_cursor/. If
+<tt/has_cursor/ is false, then we we need to draw our own
+cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
+we don't have to worry about this.
 
-  gtk_widget_draw (GTK_WIDGET(dial), NULL);
-}
+<p>
+Our <tt/print_button_press()/ function simply iterates through
+the returned list until it finds a match, then prints out
+the name of the device.
 
+<tscreen><verb>
 static void
-gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
-                             gpointer       data)
+print_button_press (guint32 deviceid)
 {
-  GtkDial *dial;
-
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+  GList *tmp_list;
 
-  dial = GTK_DIAL (data);
+  /* gdk_input_list_devices returns an internal list, so we shouldn't
+     free it afterwards */
+  tmp_list = gdk_input_list_devices();
 
-  if ((dial->old_value != adjustment->value) ||
-      (dial->old_lower != adjustment->lower) ||
-      (dial->old_upper != adjustment->upper))
+  while (tmp_list)
     {
-      gtk_dial_update (dial);
+      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
 
-      dial->old_value = adjustment->value;
-      dial->old_lower = adjustment->lower;
-      dial->old_upper = adjustment->upper;
+      if (info->deviceid == deviceid)
+       {
+         printf("Button press on device '%s'\n", info->name);
+         return;
+       }
+
+      tmp_list = tmp_list->next;
     }
 }
+</verb></tscreen>
 
-static void
-gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
-                                   gpointer       data)
-{
-  GtkDial *dial;
+That completes the changes to ``XInputize'' our program. As with
+the first version, the complete source is available at the location
+from which you got this tutorial, or from:
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
+name="http://www.gtk.org/~otaylor/gtk/tutorial/">
 
-  dial = GTK_DIAL (data);
 
-  if (dial->old_value != adjustment->value)
-    {
-      gtk_dial_update (dial);
+<sect2> Further sophistications <label id="sec_Further_Sophistications">
 
-      dial->old_value = adjustment->value;
-    }
-}
-</verb></tscreen>
+<p>
+Although our program now supports XInput quite well, it lacks some
+features we would want in a full-featured application. First, the user
+probably doesn't want to have to configure their device each time they
+run the program, so we should allow them to save the device
+configuration. This is done by iterating through the return of
+<tt/gdk_input_list_devices()/ and writing out the configuration to a
+file.
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Possible Enhancements
 <p>
+To restore the state next time the program is run, GDK provides
+functions to change device configuration:
 
-The Dial widget as we've described it so far runs about 670 lines of
-code. Although that might sound like a fair bit, we've really
-accomplished quite a bit with that much code, especially since much of
-that length is headers and boilerplate. However, there are quite a few
-more enhancements that could be made to this widget:
+<tscreen><verb>
+gdk_input_set_extension_events()
+gdk_input_set_source()
+gdk_input_set_mode()
+gdk_input_set_axes()
+gdk_input_set_key()
+</verb></tscreen>
 
-<itemize>
-<item> If you try this widget out, you'll find that there is some
-flashing as the pointer is dragged around. This is because the entire
-widget is erased every time the pointer is moved before being
-redrawn. Often, the best way to handle this problem is to draw to an
-offscreen pixmap, then copy the final results onto the screen in one
-step. (The ProgressBar widget draws itself in this fashion.)
+(The list returned from <tt/gdk_input_list_devices()/ should not be
+modified directly.) An example of doing this can be found in the
+drawing program gsumi. (Available from <htmlurl
+url="http://www.msc.cornell.edu/~otaylor/gsumi/"
+name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
+would be nice to have a standard way of doing this for all
+applications. This probably belongs at a slightly higher level than
+GTK, perhaps in the GNOME library.
 
-<item> The user should be able to use the up and down arrow keys to
-increase and decrease the value.
+<p>
+Another major ommission that we have mentioned above is the lack of
+cursor drawing. Platforms other than XFree86 currently do not allow
+simultaneously using a device as both the core pointer and directly by
+an application. See the <url
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
+name="XInput-HOWTO"> for more information about this. This means that
+applications that want to support the widest audience need to draw
+their own cursor.
 
-<item> It would be nice if the widget had buttons to increase and
-decrease the value in small or large steps. Although it would be
-possible to use embedded Button widgets for this, we would also like
-the buttons to auto-repeat when held down, as the arrows on a
-scrollbar do. Most of the code to implement this type of behavior can
-be found in the GtkRange widget.
+<p>
+An application that draws it's own cursor needs to do two things:
+determine if the current device needs a cursor drawn or not, and
+determine if the current device is in proximity. (If the current
+device is a drawing tablet, it's a nice touch to make the cursor 
+disappear when the stylus is lifted from the tablet. When the
+device is touching the stylus, that is called "in proximity.")
+The first is done by searching the device list, as we did
+to find out the device name. The second is achieved by selecting
+"proximity_out" events. An example of drawing one's own cursor is
+found in the 'testinput' program found in the GTK distribution.
 
-<item> The Dial widget could be made into a container widget with a
-single child widget positioned at the bottom between the buttons
-mentioned above. The user could then add their choice of a label or
-entry widget to display the current value of the dial.
+<!-- ***************************************************************** -->
+<sect>Tips For Writing GTK Applications
+<!-- ***************************************************************** -->
 
-</itemize>
+<p>
+This section is simply a gathering of wisdom, general style guidelines and hints to
+creating good GTK applications. It is totally useless right now cause it's
+only a topic sentence :)
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Learning More
+Use GNU autoconf and automake!  They are your friends :)  I am planning to
+make a quick intro on them here.
+
+<!-- ***************************************************************** -->
+<sect>Contributing
+<!-- ***************************************************************** -->
 
 <p>
-Only a small part of the many details involved in creating widgets
-could be described above. If you want to write your own widgets, the
-best source of examples is the GTK source itself. Ask yourself some
-questions about the widget you want to write: is it a Container
-widget? does it have its own window? is it a modification of an
-existing widget? Then find a similar widget, and start making changes.
-Good luck!
+This document, like so much other great software out there, was created for
+free by volunteers.  If you are at all knowledgeable about any aspect of GTK
+that does not already have documentation, please consider contributing to
+this document.
+<p>
+If you do decide to contribute, please mail your text to Tony Gale, 
+<tt><htmlurl url="mailto:gale@gtk.org"
+name="gale@gtk.org"></tt>. Also, be aware that the entirety of this 
+document is free, and any addition by yourself must also be free.  That is, 
+people may use any portion of your examples in their programs, and copies 
+of this document may be distributed at will etc.
+<p>
+Thank you.
 
 <!-- ***************************************************************** -->
-<sect>Scribble, A Simple Example Drawing Program
+<sect>Credits
 <!-- ***************************************************************** -->
+<p>
+I would like to thank the following for their contributions to this text.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Overview
+<itemize>
+<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
+name="chamele0n@geocities.com"></tt> for the menus tutorial.                         
 
-<p>
-In this section, we will build a simple drawing program. In the
-process, we will examine how to handle mouse events, how to draw in a
-window, and how to do drawing better by using a backing pixmap. After
-creating the simple drawing program, we will extend it by adding
-support for XInput devices, such as drawing tablets. GTK provides
-support routines which makes getting extended information, such as
-pressure and tilt, from such devices quite easy.
+<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
+name="raph@acm.org"></tt>
+for hello world ala GTK, widget packing, and general all around wisdom.
+He's also generously donated a home for this tutorial.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Event Handling
+<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
+name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program.. 
+and the ability to make it :)
 
-<p>
-The GTK signals we have already discussed are for high-level actions,
-such as a menu item being selected. However, sometimes it is useful to
-learn about lower-level occurrences, such as the mouse being moved, or
-a key being pressed. There are also GTK signals corresponding to these
-low-level <em>events</em>. The handlers for these signals have an
-extra parameter which is a pointer to a structure containing
-information about the event. For instance, motion events handlers are
-passed a pointer to a GdkEventMotion structure which looks (in part)
-like:
+<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
+name="werner.koch@guug.de"></tt> for converting the original plain text to
+SGML, and the widget class hierarchy.
 
-<tscreen><verb>
-struct _GdkEventMotion
-{
-  GdkEventType type;
-  GdkWindow *window;
-  guint32 time;
-  gdouble x;
-  gdouble y;
-  ...
-  guint state;
-  ...
-};
-</verb></tscreen>
+<item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
+name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code, and
+the table packing tutorial.
 
-<tt/type/ will be set to the event type, in this case
-<tt/GDK_MOTION_NOTIFY/, window is the window in which the event
-occured. <tt/x/ and <tt/y/ give the coordinates of the event,
-and <tt/state/ specifies the modifier state when the event
-occurred (that is, it specifies which modifier keys and mouse buttons
-were pressed.) It is the bitwise OR of some of the following:
+<item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
+name="owt1@cornell.edu"></tt> for the EventBox widget section (and
+the patch to the distro).  He's also responsible for the selections code and
+tutorial, as well as the sections on writing your own GTK widgets, and the
+example application.  Thanks a lot Owen for all you help!
 
-<tscreen><verb>
-GDK_SHIFT_MASK  
-GDK_LOCK_MASK   
-GDK_CONTROL_MASK
-GDK_MOD1_MASK   
-GDK_MOD2_MASK   
-GDK_MOD3_MASK   
-GDK_MOD4_MASK   
-GDK_MOD5_MASK   
-GDK_BUTTON1_MASK
-GDK_BUTTON2_MASK
-GDK_BUTTON3_MASK
-GDK_BUTTON4_MASK
-GDK_BUTTON5_MASK
-</verb></tscreen>
+<item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
+name="mvboom42@calvin.edu"></tt> for his wonderful work on the Notebook,
+Progress Bar, Dialogs, and File selection widgets.  Thanks a lot Mark!
+You've been a great help.
 
-<p>
-As for other signals, to determine what happens when an event occurs
-we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
-know which events we want to be notified about. To do this, we call
-the function:
+<item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
+name="timj@psynet.net"></tt> for his great job on the Lists Widget.
+Thanks Tim :)
 
-<tscreen><verb>
-void gtk_widget_set_events (GtkWidget *widget,
-                            gint      events);
-</verb></tscreen>
+<item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
+name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap tutorial.
 
-The second field specifies the events we are interested in. It
-is the bitwise OR of constants that specify different types
-of events. For future reference the event types are:
+<item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
+name="johnsonm@redhat.com"></tt> for info and code for popup menus. 
 
-<tscreen><verb>
-GDK_EXPOSURE_MASK
-GDK_POINTER_MOTION_MASK
-GDK_POINTER_MOTION_HINT_MASK
-GDK_BUTTON_MOTION_MASK     
-GDK_BUTTON1_MOTION_MASK    
-GDK_BUTTON2_MOTION_MASK    
-GDK_BUTTON3_MOTION_MASK    
-GDK_BUTTON_PRESS_MASK      
-GDK_BUTTON_RELEASE_MASK    
-GDK_KEY_PRESS_MASK         
-GDK_KEY_RELEASE_MASK       
-GDK_ENTER_NOTIFY_MASK      
-GDK_LEAVE_NOTIFY_MASK      
-GDK_FOCUS_CHANGE_MASK      
-GDK_STRUCTURE_MASK         
-GDK_PROPERTY_CHANGE_MASK   
-GDK_PROXIMITY_IN_MASK      
-GDK_PROXIMITY_OUT_MASK     
-</verb></tscreen>
+</itemize>
+<p>
+And to all of you who commented and helped refine this document.
+<p>
+Thanks.
 
-There are a few subtle points that have to be observed when calling
-<tt/gtk_widget_set_events()/. First, it must be called before the X window
-for a GTK widget is created. In practical terms, this means you
-should call it immediately after creating the widget. Second, the
-widget must have an associated X window. For efficiency, many widget
-types do not have their own window, but draw in their parent's window.
-These widgets are:
+<!-- ***************************************************************** -->
+<sect> Tutorial Copyright and Permissions Notice
+<!-- ***************************************************************** -->
 
-<tscreen><verb>
-GtkAlignment
-GtkArrow
-GtkBin
-GtkBox
-GtkImage
-GtkItem
-GtkLabel
-GtkPixmap
-GtkScrolledWindow
-GtkSeparator
-GtkTable
-GtkAspectFrame
-GtkFrame
-GtkVBox
-GtkHBox
-GtkVSeparator
-GtkHSeparator
-</verb></tscreen>
+<p>
+The GTK Tutorial is Copyright (C) 1997 Ian Main. 
 
-To capture events for these widgets, you need to use an EventBox 
-widget. See the section on   
-<ref id="sec_The_EventBox_Widget" name="The EventBox Widget"> for
-details.
+Copyright (C) 1998 Tony Gale.
+<p>
+Permission is granted to make and distribute verbatim copies of this 
+manual provided the copyright notice and this permission notice are 
+preserved on all copies.
+<P>Permission is granted to copy and distribute modified versions of 
+this document under the conditions for verbatim copying, provided that 
+this copyright notice is included exactly as in the original,
+and that the entire resulting derived work is distributed under 
+the terms of a permission notice identical to this one.
+<P>Permission is granted to copy and distribute translations of this 
+document into another language, under the above conditions for modified 
+versions.
+<P>If you are intending to incorporate this document into a published 
+work, please contact the maintainer, and we will make an effort 
+to ensure that you have the most up to date information available.
+<P>There is no guarentee that this document lives up to its intended
+purpose.  This is simply provided as a free resource.  As such,
+the authors and maintainers of the information provided within can
+not make any guarentee that the information is even accurate.
 
-<p>
-For our drawing program, we want to know when the mouse button is
-pressed and when the mouse is moved, so we specify
-<tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
-want to know when we need to redraw our window, so we specify
-<tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
-Configure event when our window size changes, we don't have to specify
-the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
-automatically specified for all windows.
+<!-- ***************************************************************** -->
+<appendix>
+<!-- ***************************************************************** -->
 
+<!-- ***************************************************************** -->
+<sect> Code Examples
+<!-- ***************************************************************** -->
 <p>
-It turns out, however, that there is a problem with just specifying
-<tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
-motion event to the event queue every time the user moves the mouse.
-Imagine that it takes us 0.1 seconds to handle a motion event, but the
-X server queues a new motion event every 0.05 seconds. We will soon
-get way behind the users drawing. If the user draws for 5 seconds,
-it will take us another 5 seconds to catch up after they release 
-the mouse button! What we would like is to only get one motion
-event for each event we process. The way to do this is to 
-specify <tt/GDK_POINTER_MOTION_HINT_MASK/. 
+Below are the code examples that are used in the above text
+which are not included in complete form elsewhere.
 
+<!-- ----------------------------------------------------------------- -->
+<sect1> Scribble
 <p>
-When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
-us a motion event the first time the pointer moves after entering
-our window, or after a button press or release event. Subsequent 
-motion events will be suppressed until we explicitely ask for
-the position of the pointer using the function:
-
 <tscreen><verb>
-GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
-                                         gint            *x,
-                                         gint            *y,
-                                         GdkModifierType *mask);
-</verb></tscreen>
+/* example-start scribble-simple scribble-simple.c */
 
-(There is another function, <tt>gtk_widget_get_pointer()</tt> which
-has a simpler interface, but turns out not to be very useful, since
-it only retrieves the position of the mouse, not whether the buttons
-are pressed.)
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
 
-<p>
-The code to set the events for our window then looks like:
+#include <gtk/gtk.h>
 
-<tscreen><verb>
-  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
-                     (GtkSignalFunc) expose_event, NULL);
-  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
-                     (GtkSignalFunc) configure_event, NULL);
-  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
-                     (GtkSignalFunc) motion_notify_event, NULL);
-  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
-                     (GtkSignalFunc) button_press_event, NULL);
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;
 
-  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
-                        | GDK_LEAVE_NOTIFY_MASK
-                        | GDK_BUTTON_PRESS_MASK
-                        | GDK_POINTER_MOTION_MASK
-                        | GDK_POINTER_MOTION_HINT_MASK);
-</verb></tscreen>
+/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+  if (pixmap)
+    gdk_pixmap_unref(pixmap);
 
-We'll save the "expose_event" and "configure_event" handlers for
-later. The "motion_notify_event" and "button_press_event" handlers
-pretty simple:
+  pixmap = gdk_pixmap_new(widget->window,
+                         widget->allocation.width,
+                         widget->allocation.height,
+                         -1);
+  gdk_draw_rectangle (pixmap,
+                     widget->style->white_gc,
+                     TRUE,
+                     0, 0,
+                     widget->allocation.width,
+                     widget->allocation.height);
+
+  return TRUE;
+}
+
+/* Redraw the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+  gdk_draw_pixmap(widget->window,
+                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                 pixmap,
+                 event->area.x, event->area.y,
+                 event->area.x, event->area.y,
+                 event->area.width, event->area.height);
+
+  return FALSE;
+}
+
+/* Draw a rectangle on the screen */
+static void
+draw_brush (GtkWidget *widget, gdouble x, gdouble y)
+{
+  GdkRectangle update_rect;
+
+  update_rect.x = x - 5;
+  update_rect.y = y - 5;
+  update_rect.width = 10;
+  update_rect.height = 10;
+  gdk_draw_rectangle (pixmap,
+                     widget->style->black_gc,
+                     TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
+}
 
-<tscreen><verb>
 static gint
 button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
   if (event->button == 1 &amp;&amp; pixmap != NULL)
-      draw_brush (widget, event->x, event->y);
+    draw_brush (widget, event->x, event->y);
 
   return TRUE;
 }
@@ -9950,732 +11793,776 @@ motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
   
   return TRUE;
 }
+
+void
+quit ()
+{
+  gtk_exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *drawing_area;
+  GtkWidget *vbox;
+
+  GtkWidget *button;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_name (window, "Test Input");
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show (vbox);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (quit), NULL);
+
+  /* Create the drawing area */
+
+  drawing_area = gtk_drawing_area_new ();
+  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
+  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+  gtk_widget_show (drawing_area);
+
+  /* Signals used to handle backing pixmap */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                     (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                     (GtkSignalFunc) configure_event, NULL);
+
+  /* Event signals */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                     (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                     (GtkSignalFunc) button_press_event, NULL);
+
+  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                        | GDK_LEAVE_NOTIFY_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_POINTER_MOTION_HINT_MASK);
+
+  /* .. And a quit button */
+  button = gtk_button_new_with_label ("Quit");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                            GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                            GTK_OBJECT (window));
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+
+  return 0;
+}
+/* example-end */
 </verb></tscreen>
 
 <!-- ----------------------------------------------------------------- -->
-<sect1> The DrawingArea Widget, And Drawing
+<sect1> GtkDial
 
+<!-- ----------------------------------------------------------------- -->
+<sect2> gtkdial.h
 <p>
-We know turn to the process of drawing on the screen. The 
-widget we use for this is the DrawingArea widget. A drawing area
-widget is essentially an X window and nothing more. It is a blank
-canvas in which we can draw whatever we like. A drawing area
-is created using the call:
-
 <tscreen><verb>
-GtkWidget* gtk_drawing_area_new        (void);
-</verb></tscreen>
+/* example-start gtkdial gtkdial.h */
 
-A default size for the widget can be specified by calling:
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__
 
-<tscreen><verb>
-void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
-                                       gint                 width,
-                                       gint                 height);
-</verb></tscreen>
 
-This default size can be overriden, as is true for all widgets,
-by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
-be overridden if the user manually resizes the the window containing
-the drawing area.
+#include <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
 
-<p>
-It should be noted that when we create a DrawingArea widget, we are,
-<em>completely</em> responsible for drawing the contents. If our
-window is obscured then uncovered, we get an exposure event and must
-redraw what was previously hidden.
 
-<p>
-Having to remember everything that was drawn on the screen so we
-can properly redraw it can, to say the least, be a nuisance. In
-addition, it can be visually distracting if portions of the
-window are cleared, then redrawn step by step. The solution to
-this problem is to use an offscreen <em>backing pixmap</em>.
-Instead of drawing directly to the screen, we draw to an image
-stored in server memory but not displayed, then when the image
-changes or new portions of the image are displayed, we copy the
-relevant portions onto the screen.
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
+
+
+typedef struct _GtkDial        GtkDial;
+typedef struct _GtkDialClass   GtkDialClass;
+
+struct _GtkDial
+{
+  GtkWidget widget;
+
+  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+  guint policy : 2;
+
+  /* Button currently pressed or 0 if none */
+  guint8 button;
 
-<p>
-To create an offscreen pixmap, we call the function:
+  /* Dimensions of dial components */
+  gint radius;
+  gint pointer_width;
 
-<tscreen><verb>
-GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
-                                        gint        width,
-                                        gint        height,
-                                        gint        depth);
-</verb></tscreen>
+  /* ID of update timer, or 0 if none */
+  guint32 timer;
 
-The <tt>window</tt> parameter specifies a GDK window that this pixmap
-takes some of its properties from. <tt>width</tt> and <tt>height</tt>
-specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
-depth</em>, that is the number of bits per pixel, for the new window.
-If the depth is specified as <tt>-1</tt>, it will match the depth
-of <tt>window</tt>.
+  /* Current angle */
+  gfloat angle;
 
-<p>
-We create the pixmap in our "configure_event" handler. This event
-is generated whenever the window changes size, including when it
-is originally created.
+  /* Old values from adjustment stored so we know when something changes */
+  gfloat old_value;
+  gfloat old_lower;
+  gfloat old_upper;
 
-<tscreen><verb>
-/* Backing pixmap for drawing area */
-static GdkPixmap *pixmap = NULL;
+  /* The adjustment object that stores the data for this dial */
+  GtkAdjustment *adjustment;
+};
 
-/* Create a new backing pixmap of the appropriate size */
-static gint
-configure_event (GtkWidget *widget, GdkEventConfigure *event)
+struct _GtkDialClass
 {
-  if (pixmap)
-    {
-      gdk_pixmap_destroy(pixmap);
-    }
-  pixmap = gdk_pixmap_new(widget->window,
-                         widget->allocation.width,
-                         widget->allocation.height,
-                         -1);
-  gdk_draw_rectangle (pixmap,
-                     widget->style->white_gc,
-                     TRUE,
-                     0, 0,
-                     widget->allocation.width,
-                     widget->allocation.height);
+  GtkWidgetClass parent_class;
+};
 
-  return TRUE;
-}
-</verb></tscreen>
 
-The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
-initially to white. We'll say more about that in a moment.
+GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
+guint          gtk_dial_get_type               (void);
+GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
+void           gtk_dial_set_update_policy      (GtkDial      *dial,
+                                               GtkUpdateType  policy);
 
-<p>
-Our exposure event handler then simply copies the relevant portion
-of the pixmap onto the screen (we determine the area we need
-to redraw by using the event->area field of the exposure event):
+void           gtk_dial_set_adjustment         (GtkDial      *dial,
+                                               GtkAdjustment *adjustment);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-<tscreen><verb>
-/* Refill the screen from the backing pixmap */
-static gint
-expose_event (GtkWidget *widget, GdkEventExpose *event)
-{
-  gdk_draw_pixmap(widget->window,
-                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-                 pixmap,
-                 event->area.x, event->area.y,
-                 event->area.x, event->area.y,
-                 event->area.width, event->area.height);
 
-  return FALSE;
-}
+#endif /* __GTK_DIAL_H__ */
+/* example-end */
 </verb></tscreen>
 
-We've now seen how to keep the screen up to date with our pixmap, but
-how do we actually draw interesting stuff on our pixmap?  There are a
-large number of calls in GTK's GDK library for drawing on
-<em>drawables</em>. A drawable is simply something that can be drawn
-upon. It can be a window, a pixmap, or a bitmap (a black and white
-image).  We've already seen two such calls above,
-<tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
-complete list is:
-
+<!-- ----------------------------------------------------------------- -->
+<sect2> gtkdial.c
+<p>
 <tscreen><verb>
-gdk_draw_line ()
-gdk_draw_rectangle ()
-gdk_draw_arc ()
-gdk_draw_polygon ()
-gdk_draw_string ()
-gdk_draw_text ()
-gdk_draw_pixmap ()
-gdk_draw_bitmap ()
-gdk_draw_image ()
-gdk_draw_points ()
-gdk_draw_segments ()
-</verb></tscreen>
+/* example-start gtkdial gtkdial.c */
 
-See the reference documentation or the header file
-<tt>&lt;gdk/gdk.h&gt;</tt> for further details on these functions.
-These functions all share the same first two arguments. The first
-argument is the drawable to draw upon, the second argument is a
-<em>graphics context</em> (GC). 
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <math.h>
+#include <stdio.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
 
-<p>
-A graphics context encapsulates information about things such as
-foreground and background color and line width. GDK has a full set of
-functions for creating and modifying graphics contexts, but to keep
-things simple we'll just use predefined graphics contexts. Each widget
-has an associated style. (Which can be modified in a gtkrc file, see
-the section GTK's rc file.) This, among other things, stores a number
-of graphics contexts. Some examples of accessing these graphics
-contexts are:
+#include "gtkdial.h"
 
-<tscreen><verb>
-widget->style->white_gc
-widget->style->black_gc
-widget->style->fg_gc[GTK_STATE_NORMAL]
-widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
-</verb></tscreen>
+#define SCROLL_DELAY_LENGTH  300
+#define DIAL_DEFAULT_SIZE 100
 
-The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
-<tt>light_gc</tt> are indexed by a parameter of type
-<tt>GtkStateType</tt> which can take on the values:
+/* Forward declararations */
 
-<tscreen><verb>
-GTK_STATE_NORMAL,
-GTK_STATE_ACTIVE,
-GTK_STATE_PRELIGHT,
-GTK_STATE_SELECTED,
-GTK_STATE_INSENSITIVE
-</verb></tscreen>
+static void gtk_dial_class_init               (GtkDialClass    *klass);
+static void gtk_dial_init                     (GtkDial         *dial);
+static void gtk_dial_destroy                  (GtkObject        *object);
+static void gtk_dial_realize                  (GtkWidget        *widget);
+static void gtk_dial_size_request             (GtkWidget      *widget,
+                                              GtkRequisition *requisition);
+static void gtk_dial_size_allocate            (GtkWidget     *widget,
+                                              GtkAllocation *allocation);
+static gint gtk_dial_expose                   (GtkWidget        *widget,
+                                               GdkEventExpose   *event);
+static gint gtk_dial_button_press             (GtkWidget        *widget,
+                                               GdkEventButton   *event);
+static gint gtk_dial_button_release           (GtkWidget        *widget,
+                                               GdkEventButton   *event);
+static gint gtk_dial_motion_notify            (GtkWidget        *widget,
+                                               GdkEventMotion   *event);
+static gint gtk_dial_timer                    (GtkDial         *dial);
+
+static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
+static void gtk_dial_update                   (GtkDial *dial);
+static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
+                                               gpointer          data);
+static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
+                                               gpointer          data);
 
-For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
-color is white and the default background color, dark blue.
+/* Local data */
 
-<p>
-Our function <tt>draw_brush()</tt>, which does the actual drawing
-on the screen, is then:
+static GtkWidgetClass *parent_class = NULL;
 
-<tscreen><verb>
-/* Draw a rectangle on the screen */
-static void
-draw_brush (GtkWidget *widget, gdouble x, gdouble y)
+guint
+gtk_dial_get_type ()
 {
-  GdkRectangle update_rect;
+  static guint dial_type = 0;
 
-  update_rect.x = x - 5;
-  update_rect.y = y - 5;
-  update_rect.width = 10;
-  update_rect.height = 10;
-  gdk_draw_rectangle (pixmap,
-                     widget->style->black_gc,
-                     TRUE,
-                     update_rect.x, update_rect.y,
-                     update_rect.width, update_rect.height);
-  gtk_widget_draw (widget, &amp;update_rect);
-}
-</verb></tscreen>
+  if (!dial_type)
+    {
+      GtkTypeInfo dial_info =
+      {
+       "GtkDial",
+       sizeof (GtkDial),
+       sizeof (GtkDialClass),
+       (GtkClassInitFunc) gtk_dial_class_init,
+       (GtkObjectInitFunc) gtk_dial_init,
+       (GtkArgSetFunc) NULL,
+       (GtkArgGetFunc) NULL,
+      };
 
-After we draw the rectangle representing the brush onto the pixmap,
-we call the function:
+      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+    }
 
-<tscreen><verb>
-void       gtk_widget_draw                (GtkWidget           *widget,
-                                          GdkRectangle        *area);
-</verb></tscreen>
+  return dial_type;
+}
 
-which notifies X that the area given by the <tt>area</tt> parameter
-needs to be updated. X will eventually generate an expose event
-(possibly combining the areas passed in several calls to
-<tt>gtk_widget_draw()</tt>) which will cause our expose event handler
-to copy the relevant portions to the screen.
+static void
+gtk_dial_class_init (GtkDialClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
 
-<p>
-We have now covered the entire drawing program except for a few
-mundane details like creating the main window. The complete
-source code is available from the location from which you got
-this tutorial, or from:
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
 
-<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
-name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+  parent_class = gtk_type_class (gtk_widget_get_type ());
 
+  object_class->destroy = gtk_dial_destroy;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Adding XInput support
+  widget_class->realize = gtk_dial_realize;
+  widget_class->expose_event = gtk_dial_expose;
+  widget_class->size_request = gtk_dial_size_request;
+  widget_class->size_allocate = gtk_dial_size_allocate;
+  widget_class->button_press_event = gtk_dial_button_press;
+  widget_class->button_release_event = gtk_dial_button_release;
+  widget_class->motion_notify_event = gtk_dial_motion_notify;
+}
+
+static void
+gtk_dial_init (GtkDial *dial)
+{
+  dial->button = 0;
+  dial->policy = GTK_UPDATE_CONTINUOUS;
+  dial->timer = 0;
+  dial->radius = 0;
+  dial->pointer_width = 0;
+  dial->angle = 0.0;
+  dial->old_value = 0.0;
+  dial->old_lower = 0.0;
+  dial->old_upper = 0.0;
+  dial->adjustment = NULL;
+}
 
-<p>
+GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+  GtkDial *dial;
 
-It is now possible to buy quite inexpensive input devices such 
-as drawing tablets, which allow drawing with a much greater
-ease of artistic expression than does a mouse. The simplest way
-to use such devices is simply as a replacement for the mouse,
-but that misses out many of the advantages of these devices,
-such as:
+  dial = gtk_type_new (gtk_dial_get_type ());
 
-<itemize>
-<item> Pressure sensitivity
-<item> Tilt reporting
-<item> Sub-pixel positioning
-<item> Multiple inputs (for example, a stylus with a point and eraser)
-</itemize>
+  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
-For information about the XInput extension, see the <htmlurl
-url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
-name="XInput-HOWTO">.
+  gtk_dial_set_adjustment (dial, adjustment);
 
-<p>
-If we examine the full definition of, for example, the GdkEventMotion
-structure, we see that it has fields to support extended device
-information.
+  return GTK_WIDGET (dial);
+}
 
-<tscreen><verb>
-struct _GdkEventMotion
+static void
+gtk_dial_destroy (GtkObject *object)
 {
-  GdkEventType type;
-  GdkWindow *window;
-  guint32 time;
-  gdouble x;
-  gdouble y;
-  gdouble pressure;
-  gdouble xtilt;
-  gdouble ytilt;
-  guint state;
-  gint16 is_hint;
-  GdkInputSource source;
-  guint32 deviceid;
-};
-</verb></tscreen>
-
-<tt/pressure/ gives the pressure as a floating point number between
-0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between 
--1 and 1, corresponding to the degree of tilt in each direction.
-<tt/source/ and <tt/deviceid/ specify the device for which the
-event occurred in two different ways. <tt/source/ gives some simple
-information about the type of device. It can take the enumeration
-values.
-
-<tscreen><verb>
-GDK_SOURCE_MOUSE
-GDK_SOURCE_PEN
-GDK_SOURCE_ERASER
-GDK_SOURCE_CURSOR
-</verb></tscreen>
+  GtkDial *dial;
 
-<tt/deviceid/ specifies a unique numeric ID for the device. This can
-be used to find out further information about the device using the
-<tt/gdk_input_list_devices()/ call (see below). The special value
-<tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
-the mouse.)
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_DIAL (object));
 
-<sect2> Enabling extended device information
+  dial = GTK_DIAL (object);
 
-<p>
-To let GTK know about our interest in the extended device information,
-we merely have to add a single line to our program:
+  if (dial->adjustment)
+    gtk_object_unref (GTK_OBJECT (dial->adjustment));
 
-<tscreen><verb>
-gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
-</verb></tscreen>
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
 
-By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
-we are interested in extension events, but only if we don't have
-to draw our own cursor. See the section <ref
-id="sec_Further_Sophistications" name="Further Sophistications"> below
-for more information about drawing the cursor. We could also 
-give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing 
-to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
-back to the default condition.
+GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
 
-<p>
-This is not completely the end of the story however. By default,
-no extension devices are enabled. We need a mechanism to allow
-users to enable and configure their extension devices. GTK provides
-the InputDialog widget to automate this process. The following
-procedure manages an InputDialog widget. It creates the dialog if
-it isn't present, and raises it to the top otherwise.
+  return dial->adjustment;
+}
 
-<tscreen><verb>
 void
-input_dialog_destroy (GtkWidget *w, gpointer data)
+gtk_dial_set_update_policy (GtkDial      *dial,
+                            GtkUpdateType  policy)
 {
-  *((GtkWidget **)data) = NULL;
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  dial->policy = policy;
 }
 
 void
-create_input_dialog ()
+gtk_dial_set_adjustment (GtkDial      *dial,
+                         GtkAdjustment *adjustment)
 {
-  static GtkWidget *inputd = NULL;
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-  if (!inputd)
+  if (dial->adjustment)
     {
-      inputd = gtk_input_dialog_new();
+      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+      gtk_object_unref (GTK_OBJECT (dial->adjustment));
+    }
 
-      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
-                         (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
-      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
-                                "clicked",
-                                (GtkSignalFunc)gtk_widget_hide,
-                                GTK_OBJECT(inputd));
-      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
+  dial->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (dial->adjustment));
 
-      gtk_widget_show (inputd);
-    }
-  else
-    {
-      if (!GTK_WIDGET_MAPPED(inputd))
-       gtk_widget_show(inputd);
-      else
-       gdk_window_raise(inputd->window);
-    }
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_changed,
+                     (gpointer) dial);
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+                     (gpointer) dial);
+
+  dial->old_value = adjustment->value;
+  dial->old_lower = adjustment->lower;
+  dial->old_upper = adjustment->upper;
+
+  gtk_dial_update (dial);
 }
-</verb></tscreen>
 
-(You might want to take note of the way we handle this dialog.  By
-connecting to the "destroy" signal, we make sure that we don't keep a
-pointer to dialog around after it is destroyed - that could lead to a
-segfault.)
+static void
+gtk_dial_realize (GtkWidget *widget)
+{
+  GtkDial *dial;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
 
-<p>
-The InputDialog has two buttons "Close" and "Save", which by default
-have no actions assigned to them. In the above function we make
-"Close" hide the dialog, hide the "Save" button, since we don't
-implement saving of XInput options in this program.
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
 
-<sect2> Using extended device information
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  dial = GTK_DIAL (widget);
 
-<p>
-Once we've enabled the device, we can just use the extended 
-device information in the extra fields of the event structures.
-In fact, it is always safe to use this information since these
-fields will have reasonable default values even when extended
-events are not enabled.
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
 
-<p>
-Once change we do have to make is to call
-<tt/gdk_input_window_get_pointer()/ instead of
-<tt/gdk_window_get_pointer/. This is necessary because
-<tt/gdk_window_get_pointer/ doesn't return the extended device
-information.
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
 
-<tscreen><verb>
-void gdk_input_window_get_pointer     (GdkWindow       *window,
-                                      guint32         deviceid,
-                                      gdouble         *x,
-                                      gdouble         *y,
-                                      gdouble         *pressure,
-                                      gdouble         *xtilt,
-                                      gdouble         *ytilt,
-                                      GdkModifierType *mask);
-</verb></tscreen>
+  widget->style = gtk_style_attach (widget->style, widget->window);
 
-When calling this function, we need to specify the device ID as
-well as the window. Usually, we'll get the device ID from the
-<tt/deviceid/ field of an event structure. Again, this function
-will return reasonable values when extension events are not
-enabled. (In this case, <tt/event->deviceid/ will have the value
-<tt/GDK_CORE_POINTER/).
+  gdk_window_set_user_data (widget->window, widget);
 
-So the basic structure of our button-press and motion event handlers,
-doesn't change much - we just need to add code to deal with the
-extended information.
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+}
+
+static void 
+gtk_dial_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
+{
+  requisition->width = DIAL_DEFAULT_SIZE;
+  requisition->height = DIAL_DEFAULT_SIZE;
+}
+
+static void
+gtk_dial_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
+{
+  GtkDial *dial;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+  g_return_if_fail (allocation != NULL);
+
+  widget->allocation = *allocation;
+  dial = GTK_DIAL (widget);
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+
+      gdk_window_move_resize (widget->window,
+                             allocation->x, allocation->y,
+                             allocation->width, allocation->height);
+
+    }
+  dial->radius = MIN(allocation->width,allocation->height) * 0.45;
+  dial->pointer_width = dial->radius / 5;
+}
 
-<tscreen><verb>
 static gint
-button_press_event (GtkWidget *widget, GdkEventButton *event)
+gtk_dial_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
 {
-  print_button_press (event->deviceid);
+  GtkDial *dial;
+  GdkPoint points[3];
+  gdouble s,c;
+  gdouble theta;
+  gint xc, yc;
+  gint tick_length;
+  gint i;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (event->count > 0)
+    return FALSE;
   
-  if (event->button == 1 &amp;&amp; pixmap != NULL)
-    draw_brush (widget, event->source, event->x, event->y, event->pressure);
+  dial = GTK_DIAL (widget);
 
-  return TRUE;
-}
+  gdk_window_clear_area (widget->window,
+                        0, 0,
+                        widget->allocation.width,
+                        widget->allocation.height);
 
-static gint
-motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
-{
-  gdouble x, y;
-  gdouble pressure;
-  GdkModifierType state;
+  xc = widget->allocation.width/2;
+  yc = widget->allocation.height/2;
 
-  if (event->is_hint)
-    gdk_input_window_get_pointer (event->window, event->deviceid,
-                                 &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
-  else
+  /* Draw ticks */
+
+  for (i=0; i<25; i++)
     {
-      x = event->x;
-      y = event->y;
-      pressure = event->pressure;
-      state = event->state;
+      theta = (i*M_PI/18. - M_PI/6.);
+      s = sin(theta);
+      c = cos(theta);
+
+      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
+      
+      gdk_draw_line (widget->window,
+                    widget->style->fg_gc[widget->state],
+                    xc + c*(dial->radius - tick_length),
+                    yc - s*(dial->radius - tick_length),
+                    xc + c*dial->radius,
+                    yc - s*dial->radius);
     }
-    
-  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
-    draw_brush (widget, event->source, x, y, pressure);
+
+  /* Draw pointer */
+
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+
+
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;
+
+  gtk_draw_polygon (widget->style,
+                   widget->window,
+                   GTK_STATE_NORMAL,
+                   GTK_SHADOW_OUT,
+                   points, 3,
+                   TRUE);
   
-  return TRUE;
+  return FALSE;
 }
-</verb></tscreen>
-
-We also need to do something with the new information. Our new
-<tt/draw_brush()/ function draws with a different color for
-each <tt/event->source/ and changes the brush size depending
-on the pressure.
 
-<tscreen><verb>
-/* Draw a rectangle on the screen, size depending on pressure,
-   and color on the type of device */
-static void
-draw_brush (GtkWidget *widget, GdkInputSource source,
-           gdouble x, gdouble y, gdouble pressure)
+static gint
+gtk_dial_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
 {
-  GdkGC *gc;
-  GdkRectangle update_rect;
+  GtkDial *dial;
+  gint dx, dy;
+  double s, c;
+  double d_parallel;
+  double d_perpendicular;
 
-  switch (source)
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  /* Determine if button press was within pointer region - we 
+     do this by computing the parallel and perpendicular distance of
+     the point where the mouse was pressed from the line passing through
+     the pointer */
+  
+  dx = event->x - widget->allocation.width / 2;
+  dy = widget->allocation.height / 2 - event->y;
+  
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  
+  d_parallel = s*dy + c*dx;
+  d_perpendicular = fabs(s*dx - c*dy);
+  
+  if (!dial->button &amp;&amp;
+      (d_perpendicular < dial->pointer_width/2) &amp;&amp;
+      (d_parallel > - dial->pointer_width))
     {
-    case GDK_SOURCE_MOUSE:
-      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
-      break;
-    case GDK_SOURCE_PEN:
-      gc = widget->style->black_gc;
-      break;
-    case GDK_SOURCE_ERASER:
-      gc = widget->style->white_gc;
-      break;
-    default:
-      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
+      gtk_grab_add (widget);
+
+      dial->button = event->button;
+
+      gtk_dial_update_mouse (dial, event->x, event->y);
     }
 
-  update_rect.x = x - 10 * pressure;
-  update_rect.y = y - 10 * pressure;
-  update_rect.width = 20 * pressure;
-  update_rect.height = 20 * pressure;
-  gdk_draw_rectangle (pixmap, gc, TRUE,
-                     update_rect.x, update_rect.y,
-                     update_rect.width, update_rect.height);
-  gtk_widget_draw (widget, &amp;update_rect);
+  return FALSE;
 }
-</verb></tscreen>
 
-<sect2> Finding out more about a device
+static gint
+gtk_dial_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+  GtkDial *dial;
 
-<p>
-As an example of how to find out more about a device, our program
-will print the name of the device that generates each button
-press. To find out the name of a device, we call the function:
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-<tscreen><verb>
-GList *gdk_input_list_devices               (void);
-</verb></tscreen>
+  dial = GTK_DIAL (widget);
 
-which returns a GList (a linked list type from the glib library)
-of GdkDeviceInfo structures. The GdkDeviceInfo strucure is defined
-as:
+  if (dial->button == event->button)
+    {
+      gtk_grab_remove (widget);
 
-<tscreen><verb>
-struct _GdkDeviceInfo
-{
-  guint32 deviceid;
-  gchar *name;
-  GdkInputSource source;
-  GdkInputMode mode;
-  gint has_cursor;
-  gint num_axes;
-  GdkAxisUse *axes;
-  gint num_keys;
-  GdkDeviceKey *keys;
-};
-</verb></tscreen>
+      dial->button = 0;
 
-Most of these fields are configuration information that you
-can ignore unless you are implemented XInput configuration
-saving. The we are interested in here is <tt/name/ which is
-simply the name that X assigns to the device. The other field
-that isn't configuration information is <tt/has_cursor/. If
-<tt/has_cursor/ is false, then we we need to draw our own
-cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
-we don't have to worry about this.
+      if (dial->policy == GTK_UPDATE_DELAYED)
+       gtk_timeout_remove (dial->timer);
+      
+      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
+         (dial->old_value != dial->adjustment->value))
+       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
 
-<p>
-Our <tt/print_button_press()/ function simply iterates through
-the returned list until it finds a match, then prints out
-the name of the device.
+  return FALSE;
+}
 
-<tscreen><verb>
-static void
-print_button_press (guint32 deviceid)
+static gint
+gtk_dial_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
 {
-  GList *tmp_list;
+  GtkDial *dial;
+  GdkModifierType mods;
+  gint x, y, mask;
 
-  /* gdk_input_list_devices returns an internal list, so we shouldn't
-     free it afterwards */
-  tmp_list = gdk_input_list_devices();
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  while (tmp_list)
+  dial = GTK_DIAL (widget);
+
+  if (dial->button != 0)
     {
-      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
+      x = event->x;
+      y = event->y;
 
-      if (info->deviceid == deviceid)
+      if (event->is_hint || (event->window != widget->window))
+       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
+
+      switch (dial->button)
        {
-         printf("Button press on device '%s'\n", info->name);
-         return;
+       case 1:
+         mask = GDK_BUTTON1_MASK;
+         break;
+       case 2:
+         mask = GDK_BUTTON2_MASK;
+         break;
+       case 3:
+         mask = GDK_BUTTON3_MASK;
+         break;
+       default:
+         mask = 0;
+         break;
        }
 
-      tmp_list = tmp_list->next;
+      if (mods &amp; mask)
+       gtk_dial_update_mouse (dial, x,y);
     }
+
+  return FALSE;
 }
-</verb></tscreen>
 
-That completes the changes to ``XInputize'' our program. As with
-the first version, the complete source is available at the location
-from which you got this tutorial, or from:
+static gint
+gtk_dial_timer (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
 
-<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
-name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+  if (dial->policy == GTK_UPDATE_DELAYED)
+    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
+  return FALSE;
+}
 
-<sect2> Further sophistications <label id="sec_Further_Sophistications">
+static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+  gint xc, yc;
+  gfloat old_value;
 
-<p>
-Although our program now supports XInput quite well, it lacks some
-features we would want in a full-featured application. First, the user
-probably doesn't want to have to configure their device each time they
-run the program, so we should allow them to save the device
-configuration. This is done by iterating through the return of
-<tt/gdk_input_list_devices()/ and writing out the configuration to a
-file.
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-<p>
-To restore the state next time the program is run, GDK provides
-functions to change device configuration:
+  xc = GTK_WIDGET(dial)->allocation.width / 2;
+  yc = GTK_WIDGET(dial)->allocation.height / 2;
 
-<tscreen><verb>
-gdk_input_set_extension_events()
-gdk_input_set_source()
-gdk_input_set_mode()
-gdk_input_set_axes()
-gdk_input_set_key()
-</verb></tscreen>
+  old_value = dial->adjustment->value;
+  dial->angle = atan2(yc-y, x-xc);
 
-(The list returned from <tt/gdk_input_list_devices()/ should not be
-modified directly.) An example of doing this can be found in the
-drawing program gsumi. (Available from <htmlurl
-url="http://www.msc.cornell.edu/~otaylor/gsumi/"
-name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
-would be nice to have a standard way of doing this for all
-applications. This probably belongs at a slightly higher level than
-GTK, perhaps in the GNOME library.
+  if (dial->angle < -M_PI/2.)
+    dial->angle += 2*M_PI;
 
-<p>
-Another major ommission that we have mentioned above is the lack of
-cursor drawing. Platforms other than XFree86 currently do not allow
-simultaneously using a device as both the core pointer and directly by
-an application. See the <url
-url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
-name="XInput-HOWTO"> for more information about this. This means that
-applications that want to support the widest audience need to draw
-their own cursor.
+  if (dial->angle < -M_PI/6)
+    dial->angle = -M_PI/6;
 
-<p>
-An application that draws it's own cursor needs to do two things:
-determine if the current device needs a cursor drawn or not, and
-determine if the current device is in proximity. (If the current
-device is a drawing tablet, it's a nice touch to make the cursor 
-disappear when the stylus is lifted from the tablet. When the
-device is touching the stylus, that is called "in proximity.")
-The first is done by searching the device list, as we did
-to find out the device name. The second is achieved by selecting
-"proximity_out" events. An example of drawing one's own cursor is
-found in the 'testinput' program found in the GTK distribution.
+  if (dial->angle > 7.*M_PI/6.)
+    dial->angle = 7.*M_PI/6.;
 
-<!-- ***************************************************************** -->
-<sect>Tips For Writing GTK Applications
-<!-- ***************************************************************** -->
+  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
 
-<p>
-This section is simply a gathering of wisdom, general style guidelines and hints to
-creating good GTK applications. It is totally useless right now cause it's
-only a topic sentence :)
+  if (dial->adjustment->value != old_value)
+    {
+      if (dial->policy == GTK_UPDATE_CONTINUOUS)
+       {
+         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+       }
+      else
+       {
+         gtk_widget_draw (GTK_WIDGET(dial), NULL);
 
-Use GNU autoconf and automake!  They are your friends :)  I am planning to
-make a quick intro on them here.
+         if (dial->policy == GTK_UPDATE_DELAYED)
+           {
+             if (dial->timer)
+               gtk_timeout_remove (dial->timer);
 
-<!-- ***************************************************************** -->
-<sect>Contributing
-<!-- ***************************************************************** -->
+             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+                                            (GtkFunction) gtk_dial_timer,
+                                            (gpointer) dial);
+           }
+       }
+    }
+}
 
-<p>
-This document, like so much other great software out there, was created for
-free by volunteers.  If you are at all knowledgeable about any aspect of GTK
-that does not already have documentation, please consider contributing to
-this document.
-<p>
-If you do decide to contribute, please mail your text to Tony Gale, 
-<tt><htmlurl url="mailto:gale@gtk.org"
-name="gale@gtk.org"></tt>. Also, be aware that the entirety of this 
-document is free, and any addition by yourself must also be free.  That is, 
-people may use any portion of your examples in their programs, and copies 
-of this document may be distributed at will etc.
-<p>
-Thank you.
+static void
+gtk_dial_update (GtkDial *dial)
+{
+  gfloat new_value;
+  
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-<!-- ***************************************************************** -->
-<sect>Credits
-<!-- ***************************************************************** -->
-<p>
-I would like to thank the following for their contributions to this text.
+  new_value = dial->adjustment->value;
+  
+  if (new_value < dial->adjustment->lower)
+    new_value = dial->adjustment->lower;
 
-<itemize>
-<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
-name="chamele0n@geocities.com"></tt> for the menus tutorial.                         
+  if (new_value > dial->adjustment->upper)
+    new_value = dial->adjustment->upper;
 
-<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
-name="raph@acm.org"></tt>
-for hello world ala GTK, widget packing, and general all around wisdom.
-He's also generously donated a home for this tutorial.
+  if (new_value != dial->adjustment->value)
+    {
+      dial->adjustment->value = new_value;
+      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
 
-<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
-name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program.. 
-and the ability to make it :)
+  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+    (dial->adjustment->upper - dial->adjustment->lower);
 
-<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
-name="werner.koch@guug.de"></tt> for converting the original plain text to
-SGML, and the widget class hierarchy.
+  gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}
 
-<item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
-name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code, and
-the table packing tutorial.
+static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
+{
+  GtkDial *dial;
 
-<item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
-name="owt1@cornell.edu"></tt> for the EventBox widget section (and
-the patch to the distro).  He's also responsible for the selections code and
-tutorial, as well as the sections on writing your own GTK widgets, and the
-example application.  Thanks a lot Owen for all you help!
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-<item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
-name="mvboom42@calvin.edu"></tt> for his wonderful work on the Notebook,
-Progress Bar, Dialogs, and File selection widgets.  Thanks a lot Mark!
-You've been a great help.
+  dial = GTK_DIAL (data);
 
-<item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
-name="timj@psynet.net"></tt> for his great job on the Lists Widget.
-Thanks Tim :)
+  if ((dial->old_value != adjustment->value) ||
+      (dial->old_lower != adjustment->lower) ||
+      (dial->old_upper != adjustment->upper))
+    {
+      gtk_dial_update (dial);
 
-<item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
-name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap tutorial.
+      dial->old_value = adjustment->value;
+      dial->old_lower = adjustment->lower;
+      dial->old_upper = adjustment->upper;
+    }
+}
 
-<item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
-name="johnsonm@redhat.com"></tt> for info and code for popup menus. 
+static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
+{
+  GtkDial *dial;
 
-</itemize>
-<p>
-And to all of you who commented and helped refine this document.
-<p>
-Thanks.
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-<!-- ***************************************************************** -->
-<sect> Tutorial Copyright and Permissions Notice
-<!-- ***************************************************************** -->
+  dial = GTK_DIAL (data);
 
-<p>
-The GTK Tutorial is Copyright (C) 1997 Ian Main. 
+  if (dial->old_value != adjustment->value)
+    {
+      gtk_dial_update (dial);
 
-Copyright (C) 1998 Tony Gale.
-<p>
-Permission is granted to make and distribute verbatim copies of this 
-manual provided the copyright notice and this permission notice are 
-preserved on all copies.
-<P>Permission is granted to copy and distribute modified versions of 
-this document under the conditions for verbatim copying, provided that 
-this copyright notice is included exactly as in the original,
-and that the entire resulting derived work is distributed under 
-the terms of a permission notice identical to this one.
-<P>Permission is granted to copy and distribute translations of this 
-document into another language, under the above conditions for modified 
-versions.
-<P>If you are intending to incorporate this document into a published 
-work, please contact the maintainer, and we will make an effort 
-to ensure that you have the most up to date information available.
-<P>There is no guarentee that this document lives up to its intended
-purpose.  This is simply provided as a free resource.  As such,
-the authors and maintainers of the information provided within can
-not make any guarentee that the information is even accurate.
+      dial->old_value = adjustment->value;
+    }
+}
+/* example-end */
+</verb></tscreen>
 </article>
index fe93a7cbac2030bbbd46d8f01d7b5612c30aedd8..d519ddbfc6c546a350974722120d2367216179b6 100644 (file)
@@ -10,7 +10,7 @@
                              name="&lt;imain@gtk.org&gt;"></tt>,
 Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
                              name="&lt;gale@gtk.org&gt;"></tt>
-<date>June 24th, 1998
+<date>July 25th, 1998
 
 <!-- ***************************************************************** -->
 <sect>Introduction
@@ -70,6 +70,9 @@ You can also view other sources of GTK information on http://www.gtk.org/
 GTK uses GNU autoconf for
 configuration.  Once untar'd, type ./configure --help to see a list of options.
 
+Th GTK source distribution also contains the complete source to all of the
+examples used in this tutorial, along with Makefiles to aid compilation.
+
 To begin our introduction to GTK, we'll start with the simplest program 
 possible.  This program will
 create a 200x200 pixel window and has no way of exiting except to be
@@ -272,6 +275,9 @@ directories for the compiler to look in, and <tt>gtk-config --libs</>
 will output the list of libraries for the compiler to link with and
 the directories to find them in.
 
+Note that the type of single quote used in the compile command above
+is significant.
+
 The libraries that are usually linked in are:
 <itemize>
 <item>The GTK library (-lgtk), the widget library, based on top of GDK.
@@ -985,6 +991,7 @@ yourself and play with it.
 <tscreen><verb>
 /* example-start packbox packbox.c */
 
+#include <stdio.h>
 #include "gtk/gtk.h"
 
 void
@@ -5705,4227 +5712,6063 @@ Please see the GtkList example on this, which covers the usage of a
 GtkListItem as well.
 
 <!-- ***************************************************************** -->
-<sect>Menu Widgets
+<sect> Tree Widget<label id="sec_Tree_Widgets">
 <!-- ***************************************************************** -->
 <p>
-There are two ways to create menus, there's the easy way, and there's the
-hard way. Both have their uses, but you can usually use the menufactory
-(the easy way). The "hard" way is to create all the menus using the calls
-directly. The easy way is to use the gtk_menu_factory calls. This is
-much simpler, but there are advantages and disadvantages to each approach.
 
-The menufactory is much easier to use, and to add new menus to, although
-writing a few wrapper functions to create menus using the manual method 
-could go a long way towards usability. With the menufactory, it is not 
-possible to add images or the character '/' to the menus.
+The purpose of tree widgets is to display hierarchically-organized
+data. The GtkTree widget itself is a vertical container for widgets
+of type GtkTreeItem. GtkTree itself is not terribly different from
+GtkList - both are derived directly from GtkContainer, and the
+GtkContainer methods work in the same way on GtkTree widgets as on
+GtkList widgets. The difference is that GtkTree widgets can be nested
+within other GtkTree widgets. We'll see how to do this shortly.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Manual Menu Creation
+The GtkTree widget has its own window, and defaults to a white
+background, as does GtkList. Also, most of the GtkTree methods work
+in the same way as the corresponding GtkList ones. However, GtkTree
+is not derived from GtkList, so you cannot use them interchangeably.
+
+<sect1> Creating a Tree
 <p>
-In the true tradition of teaching, we'll show you the hard
-way first. <tt>:)</>
+A GtkTree is created in the usual way, using:
 
-There are three widgets that go into making a menubar and submenus:
-<itemize>
-<item>a menu item, which is what the user wants to select, e.g. 'Save'
-<item>a menu, which acts as a container for the menu items, and
-<item>a menubar, which is a container for each of the individual menus,
-</itemize>
+<tscreen><verb>
+GtkWidget* gtk_tree_new( void );
+</verb></tscreen>
 
-This is slightly complicated by the fact that menu item widgets are used
-for two different things. They are both the widets that are packed into
-the menu, and the widget that is packed into the menubar, which,
-when selected, activiates the menu.
+Like the GtkList widget, a GtkTree will simply keep growing as more
+items are added to it, as well as when subtrees are expanded.
+For this reason, they are almost always packed into a
+GtkScrolledWindow. You might want to use gtk_widget_set_usize() on
+the scrolled window to ensure that it is big enough to see the tree's
+items, as the default size for GtkScrolledWindow is quite small.
 
-Let's look at the functions that are used to create menus and menubars.
-This first function is used to create a new menubar.
+Now that you have a tree, you'll probably want to add some items to
+it.  <ref id="sec_Tree_Item_Widget" name="The Tree Item Widget"> below
+explains the gory details of GtkTreeItem. For now, it'll suffice to
+create one, using:
 
 <tscreen><verb>
-GtkWidget *gtk_menu_bar_new( void );
+GtkWidget* gtk_tree_item_new_with_label( gchar *label );
 </verb></tscreen>
 
-This rather self explanatory function creates a new menubar.  You use
-gtk_container_add to pack this into a window, or the box_pack functions to
-pack it into a box - the same as buttons.
+You can then add it to the tree using one of the following (see
+<ref id="sec_GtkTree_Functions" name="Functions and Macros">
+below for more options):
 
 <tscreen><verb>
-GtkWidget *gtk_menu_new( void );
+void gtk_tree_append( GtkTree    *tree,
+                       GtkWidget *tree_item );
+
+void gtk_tree_prepend( GtkTree   *tree,
+                       GtkWidget *tree_item );
 </verb></tscreen>
 
-This function returns a pointer to a new menu, it is never actually shown
-(with gtk_widget_show), it is just a container for the menu items.  Hopefully this will
-become more clear when you look at the example below.
+Note that you must add items to a GtkTree one at a time - there is no
+equivalent to gtk_list_*_items().
 
-The next two calls are used to create menu items that are packed into
-the menu (and menubar).
+<sect1> Adding a Subtree
+<p>
+A subtree is created like any other GtkTree widget. A subtree is added
+to another tree beneath a tree item, using:
 
 <tscreen><verb>
-GtkWidget *gtk_menu_item_new( void );
+void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
+                                GtkWidget   *subtree );
 </verb></tscreen>
 
-and
+You do not need to call gtk_widget_show() on a subtree before or after
+adding it to a GtkTreeItem. However, you <em>must</em> have added the
+GtkTreeItem in question to a parent tree before calling
+gtk_tree_item_set_subtree(). This is because, technically, the parent
+of the subtree is <em>not</em> the GtkTreeItem which "owns" it, but
+rather the GtkTree which holds that GtkTreeItem.
+
+When you add a subtree to a GtkTreeItem, a plus or minus sign appears
+beside it, which the user can click on to "expand" or "collapse" it,
+meaning, to show or hide its subtree. GtkTreeItems are collapsed by
+default. Note that when you collapse a GtkTreeItem, any selected
+items in its subtree remain selected, which may not be what the user
+expects.
+
+<sect1> Handling the Selection List
+<p>
+As with GtkList, the GtkTree type has a <tt>selection</tt> field, and
+it is possible to control the behaviour of the tree (somewhat) by
+setting the selection type using:
 
 <tscreen><verb>
-GtkWidget *gtk_menu_item_new_with_label( const char *label );
+void gtk_tree_set_selection_mode( GtkTree          *tree,
+                                  GtkSelectionMode  mode );
 </verb></tscreen>
 
-These calls are used to create the menu items that are to be displayed.
-Remember to differentiate between a "menu" as created with gtk_menu_new
-and a "menu item" as created by the gtk_menu_item_new functions. The
-menu item will be an actual button with an associated action,
-whereas a menu will be a container holding menu items.
+The semantics associated with the various selection modes are
+described in the section on the GtkList widget.  As with the GtkList
+widget, the "select_child", "unselect_child" (not really - see <ref
+id="sec_GtkTree_Signals" name="Signals"> below for an explanation),
+and "selection_changed" signals are emitted when list items are
+selected or unselected.  However, in order to take advantage of these
+signals, you need to know <em>which</em> GtkTree widget they will be
+emitted by, and where to find the list of selected items.
 
-The gtk_menu_new_with_label and gtk_menu_new functions are just as you'd expect after
-reading about the buttons. One creates a new menu item with a label
-already packed into it, and the other just creates a blank menu item.
+This is a source of potential confusion. The best way to explain this
+is that though all GtkTree widgets are created equal, some are more
+equal than others. All GtkTree widgets have their own X window, and
+can therefore receive events such as mouse clicks (if their
+GtkTreeItems or their children don't catch them first!). However, to
+make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types
+behave in a sane manner, the list of selected items is specific to the
+topmost GtkTree widget in a hierarchy, known as the "root tree".
 
-Once you've created a menu item you have to put it into a menu. This is 
-done using the function gtk_menu_append. In order to capture when the item
-is selected by the user, we need to connect to the <tt/activate/ signal in
-the usual way. So, if we wanted to create a standard <tt/File/ menu, with
-the options <tt/Open/, <tt/Save/ and <tt/Quit/ the code would look something like
+Thus, accessing the <tt>selection</tt>field directly in an arbitrary
+GtkTree widget is not a good idea unless you <em>know</em> it's the
+root tree.  Instead, use the GTK_TREE_SELECTION (Tree) macro, which
+gives the root tree's selection list as a GList pointer. Of course,
+this list can include items that are not in the subtree in question if 
+the selection type is GTK_SELECTION_MULTIPLE.
+
+Finally, the "select_child" (and "unselect_child", in theory) signals
+are emitted by all trees, but the "selection_changed" signal is only
+emitted by the root tree. Consequently, if you want to handle the
+"select_child" signal for a tree and all its subtrees, you will have
+to call gtk_signal_connect() for every subtree.
+
+<sect1> Tree Widget Internals
+<p>
+The GtkTree's struct definition looks like this:
 
 <tscreen><verb>
-file_menu = gtk_menu_new();    /* Don't need to show menus */
+struct _GtkTree
+{
+  GtkContainer container;
 
-/* Create the menu items */
-open_item = gtk_menu_item_new_with_label("Open");
-save_item = gtk_menu_item_new_with_label("Save");
-quit_item = gtk_menu_item_new_with_label("Quit");
+  GList *children;
+  
+  GtkTree* root_tree; /* owner of selection list */
+  GtkWidget* tree_owner;
+  GList *selection;
+  guint level;
+  guint indent_value;
+  guint current_indent;
+  guint selection_mode : 2;
+  guint view_mode : 1;
+  guint view_line : 1;
+};
+</verb></tscreen>
 
-/* Add them to the menu */
-gtk_menu_append( GTK_MENU(file_menu), open_item);
-gtk_menu_append( GTK_MENU(file_menu), save_item);
-gtk_menu_append( GTK_MENU(file_menu), quit_item);
+The perils associated with accessing the <tt>selection</tt> field
+directly have already been mentioned.  The other important fields of
+the struct can also be accessed with handy macros or class functions.
+GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates
+whether a tree is the root tree in a GtkTree hierarchy, while
+GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type
+GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want
+to use one of the gtk_widget_*() functions on it).
 
-/* Attach the callback functions to the activate signal */
-gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
-                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
-gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
-                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
+Instead of directly accessing the children field of a GtkTree widget,
+it's probably best to cast it using GTK_CONTAINER (Tree), and pass it
+to the gtk_container_children() function. This creates a duplicate of
+the original list, so it's advisable to free it up using g_list_free() 
+after you're done with it, or to iterate on it destructively, like
+this:
 
-/* We can attach the Quit menu item to our exit function */
-gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
-                          GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
+<tscreen><verb>
+children = gtk_container_children (GTK_CONTAINER (tree));
+while (children) {
+  do_something_nice (GTK_TREE_ITEM (children->data));
+  children = g_list_remove_link (children, children);
+}
+</verb></tscreen>
 
-/* We do need to show menu items */
-gtk_widget_show( open_item );
-gtk_widget_show( save_item );
-gtk_widget_show( quit_item );
+The <tt>tree_owner</tt> field is defined only in subtrees, where it
+points to the GtkTreeItem widget which holds the tree in question.
+The <tt>level</tt> field indicates how deeply nested a particular tree
+is; root trees have level 0, and each successive level of subtrees has
+a level one greater than the parent level.  This field is set only
+after a GtkTree widget is actually mapped (i.e. drawn on the screen).
+
+<sect2> Signals<label id="sec_GtkTree_Signals">
+<p>
+<tscreen><verb>
+void selection_changed( GtkTree *tree );
 </verb></tscreen>
 
-At this point we have our menu. Now we need to create a menubar and a menu
-item for the <tt/File/ entry, to which we add our menu. The code looks like this 
+This signal will be emitted whenever the <tt>selection</tt> field of a
+GtkTree has changed. This happens when a child of the GtkTree is
+selected or deselected.
 
 <tscreen><verb>
-menu_bar = gtk_menu_bar_new();
-gtk_container_add( GTK_CONTAINER(window), menu_bar);
-gtk_widget_show( menu_bar );
+void select_child( GtkTree   *tree,
+                   GtkWidget *child );
+</verb></tscreen>
 
-file_item = gtk_menu_item_new_with_label("File");
-gtk_widget_show(file_item);
+This signal is emitted when a child of the GtkTree is about to get
+selected. This happens on calls to gtk_tree_select_item(),
+gtk_tree_select_child(), on <em>all</em> button presses and calls to
+gtk_tree_item_toggle() and gtk_item_toggle().  It may sometimes be
+indirectly triggered on other occasions where children get added to or
+removed from the GtkTree.
+
+<tscreen><verb>
+void unselect_child (GtkTree   *tree,
+                     GtkWidget *child);
 </verb></tscreen>
 
-Now we need to associate the menu with <tt/file_item/. This is done with the
-function
+This signal is emitted when a child of the GtkTree is about to get
+deselected. As of GTK+ 1.0.4, this seems to only occur on calls to
+gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on
+other occasions, but <em>not</em> when a button press deselects a
+child, nor on emission of the "toggle" signal by gtk_item_toggle().
 
-<tscreen>
-void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
-                                GtkWidget   *submenu );
-</tscreen>
+<sect2> Functions and Macros<label id="sec_GtkTree_Functions">
+<p>
+<tscreen><verb>
+guint gtk_tree_get_type( void );
+</verb></tscreen>
 
-So, our example would continue with
+Returns the `GtkTree' type identifier.
 
 <tscreen><verb>
-gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
+GtkWidget* gtk_tree_new( void );
 </verb></tscreen>
 
-All that is left to do is to add the menu to the menubar, which is accomplished
-using the function
+Create a new GtkTree object. The new widget is returned as a pointer to a
+GtkWidget object. NULL is returned on failure.
 
-<tscreen>
-void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
-</tscreen>
+<tscreen><verb>
+void gtk_tree_append( GtkTree   *tree,
+                      GtkWidget *tree_item );
+</verb></tscreen>
 
-which in our case looks like this:
+Append a tree item to a GtkTree.
 
 <tscreen><verb>
-gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
+void gtk_tree_prepend( GtkTree   *tree,
+                       GtkWidget *tree_item );
 </verb></tscreen>
 
-If we wanted the menu right justified on the menubar, such as help menus
-often are, we can use the following function (again on <tt/file_item/
-in the current example) before attaching it to the menubar.
+Prepend a tree item to a GtkTree.
 
 <tscreen><verb>
-void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
+void gtk_tree_insert( GtkTree   *tree,
+                      GtkWidget *tree_item,
+                      gint       position );
 </verb></tscreen>
 
-Here is a summary of the steps needed to create a menu bar with menus attached:
+Insert a tree item into a GtkTree at the position in the list
+specified by <tt>position.</tt>
 
-<itemize>
-<item> Create a new menu using gtk_menu_new()
-<item> Use multiple calls to gtk_menu_item_new() for each item you wish to have
-on your menu. And use gtk_menu_append() to put each of these new items on 
-to the menu.
-<item> Create a menu item using gtk_menu_item_new(). This will be the root of
-the menu, the text appearing here will be on the menubar itself.
-<item>Use gtk_menu_item_set_submenu() to attach the menu to the root menu 
-item (the one created in the above step).
-<item> Create a new menubar using gtk_menu_bar_new. This step only needs
-to be done once when creating a series of menus on one menu bar.
-<item> Use gtk_menu_bar_append to put the root menu onto the menubar.
-</itemize>
+<tscreen><verb>
+void gtk_tree_remove_items( GtkTree *tree,
+                            GList   *items );
+</verb></tscreen>
 
-Creating a popup menu is nearly the same. The difference is that the
-menu is not posted `automatically' by a menubar, but explicitly by calling
-the function gtk_menu_popup() from a button-press event, for example.
-Take these steps:
+Remove a list of items (in the form of a GList *) from a GtkTree.
+Note that removing an item from a tree dereferences (and thus usually)
+destroys it <em>and</em> its subtree, if it has one, <em>and</em> all
+subtrees in that subtree.  If you want to remove only one item, you
+can use gtk_container_remove().
 
-<itemize>
-<item>Create an event handling function. It needs to have the prototype
-<tscreen>
-static gint handler( GtkWidget *widget,
-                     GdkEvent  *event );
-</tscreen>
-and it will use the event to find out where to pop up the menu.
-<item>In the event handler, if the event is a mouse button press, treat
-<tt>event</tt> as a button event (which it is) and use it as
-shown in the sample code to pass information to gtk_menu_popup().
-<item>Bind that event handler to a widget with
-<tscreen>
-gtk_signal_connect_object(GTK_OBJECT(widget), "event",
-                          GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
-</tscreen>
-where <tt>widget</tt> is the widget you are binding to, <tt>handler</tt>
-is the handling function, and <tt>menu</tt> is a menu created with
-gtk_menu_new().  This can be a menu which is also posted by a menu bar,
-as shown in the sample code.
-</itemize>
+<tscreen><verb>
+void gtk_tree_clear_items( GtkTree *tree,
+                           gint     start,
+                           gint     end );
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Manual Menu Example
-<p>
-That should about do it.  Let's take a look at an example to help clarify.
+Remove the items from position <tt>start</tt> to position <tt>end</tt>
+from a GtkTree.  The same warning about dereferencing applies here, as
+gtk_tree_clear_items() simply constructs a list and passes it to
+gtk_tree_remove_items().
 
 <tscreen><verb>
-/* example-start menu menu.c */
+void gtk_tree_select_item( GtkTree *tree,
+                           gint     item );
+</verb></tscreen>
 
-#include <gtk/gtk.h>
+Emits the "select_item" signal for the child at position
+<tt>item</tt>, thus selecting the child (unless you unselect it in a
+signal handler...)
 
-static gint button_press (GtkWidget *, GdkEvent *);
-static void menuitem_response (gchar *);
+<tscreen><verb>
+void gtk_tree_unselect_item( GtkTree *tree,
+                             gint     item );
+</verb></tscreen>
 
-int main (int argc, char *argv[])
-{
+Emits the "unselect_item" signal for the child at position
+<tt>item</tt>, thus unselecting the child.
 
-    GtkWidget *window;
-    GtkWidget *menu;
-    GtkWidget *menu_bar;
-    GtkWidget *root_menu;
-    GtkWidget *menu_items;
-    GtkWidget *vbox;
-    GtkWidget *button;
-    char buf[128];
-    int i;
+<tscreen><verb>
+void gtk_tree_select_child( GtkTree   *tree,
+                            GtkWidget *tree_item );
+</verb></tscreen>
 
-    gtk_init (&amp;argc, &amp;argv);
+Emits the "select_item" signal for the child <tt>tree_item</tt>, thus
+selecting it.
 
-    /* create a new window */
-    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
-    gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
-    gtk_signal_connect(GTK_OBJECT (window), "delete_event",
-                       (GtkSignalFunc) gtk_main_quit, NULL);
+<tscreen><verb>
+void gtk_tree_unselect_child( GtkTree   *tree,
+                              GtkWidget *tree_item );
+</verb></tscreen>
 
-    /* Init the menu-widget, and remember -- never
-     * gtk_show_widget() the menu widget!! 
-     * This is the menu that holds the menu items, the one that
-     * will pop up when you click on the "Root Menu" in the app */
-    menu = gtk_menu_new();
+Emits the "unselect_item" signal for the child <tt>tree_item</tt>,
+thus unselecting it.
 
-    /* Next we make a little loop that makes three menu-entries for "test-menu".
-     * Notice the call to gtk_menu_append.  Here we are adding a list of
-     * menu items to our menu.  Normally, we'd also catch the "clicked"
-     * signal on each of the menu items and setup a callback for it,
-     * but it's omitted here to save space. */
+<tscreen><verb>
+gint gtk_tree_child_position( GtkTree   *tree,
+                              GtkWidget *child );
+</verb></tscreen>
 
-    for(i = 0; i < 3; i++)
-        {
-            /* Copy the names to the buf. */
-            sprintf(buf, "Test-undermenu - %d", i);
+Returns the position in the tree of <tt>child</tt>, unless
+<tt>child</tt> is not in the tree, in which case it returns -1.
 
-            /* Create a new menu-item with a name... */
-            menu_items = gtk_menu_item_new_with_label(buf);
+<tscreen><verb>
+void gtk_tree_set_selection_mode( GtkTree          *tree,
+                                  GtkSelectionMode  mode );
+</verb></tscreen>
 
-            /* ...and add it to the menu. */
-            gtk_menu_append(GTK_MENU (menu), menu_items);
+Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the
+default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or
+GTK_SELECTION_EXTENDED. This is only defined for root trees, which
+makes sense, since the root tree "owns" the selection. Setting it for
+subtrees has no effect at all; the value is simply ignored.
 
-           /* Do something interesting when the menuitem is selected */
-           gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
-               GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
+<tscreen><verb>
+void gtk_tree_set_view_mode( GtkTree         *tree,
+                             GtkTreeViewMode  mode ); 
+</verb></tscreen>
 
-            /* Show the widget */
-            gtk_widget_show(menu_items);
-        }
+Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the
+default) or GTK_TREE_VIEW_ITEM.  The view mode propagates from a tree
+to its subtrees, and can't be set exclusively to a subtree (this is
+not exactly true - see the example code comments).
 
-    /* This is the root menu, and will be the label
-     * displayed on the menu bar.  There won't be a signal handler attached,
-     * as it only pops up the rest of the menu when pressed. */
-    root_menu = gtk_menu_item_new_with_label("Root Menu");
+The term "view mode" is rather ambiguous - basically, it controls the
+way the hilight is drawn when one of a tree's children is selected.
+If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is
+hilighted, while for GTK_TREE_VIEW_ITEM, only the child widget
+(i.e. usually the label) is hilighted.
 
-    gtk_widget_show(root_menu);
+<tscreen><verb>
+void gtk_tree_set_view_lines( GtkTree *tree,
+                              guint    flag );
+</verb></tscreen>
 
-    /* Now we specify that we want our newly created "menu" to be the menu
-     * for the "root menu" */
-    gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
+Controls whether connecting lines between tree items are drawn.
+<tt>flag</tt> is either TRUE, in which case they are, or FALSE, in
+which case they aren't.
 
-    /* A vbox to put a menu and a button in: */
-    vbox = gtk_vbox_new(FALSE, 0);
-    gtk_container_add(GTK_CONTAINER(window), vbox);
-    gtk_widget_show(vbox);
+<tscreen><verb>
+GtkTree *GTK_TREE (gpointer obj);
+</verb></tscreen>
 
-    /* Create a menu-bar to hold the menus and add it to our main window */
-    menu_bar = gtk_menu_bar_new();
-    gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
-    gtk_widget_show(menu_bar);
+Cast a generic pointer to `GtkTree *'.
 
-    /* Create a button to which to attach menu as a popup */
-    button = gtk_button_new_with_label("press me");
-    gtk_signal_connect_object(GTK_OBJECT(button), "event",
-       GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
-    gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
-    gtk_widget_show(button);
+<tscreen><verb>
+GtkTreeClass *GTK_TREE_CLASS (gpointer class);
+</verb></tscreen>
 
-    /* And finally we append the menu-item to the menu-bar -- this is the
-     * "root" menu-item I have been raving about =) */
-    gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
+Cast a generic pointer to `GtkTreeClass*'.
 
-    /* always display the window as the last step so it all splashes on
-     * the screen at once. */
-    gtk_widget_show(window);
+<tscreen><verb>
+gint GTK_IS_TREE (gpointer obj);
+</verb></tscreen>
 
-    gtk_main ();
+Determine if a generic pointer refers to a `GtkTree' object.
 
-    return 0;
-}
+<tscreen><verb>
+gint GTK_IS_ROOT_TREE (gpointer obj)
+</verb></tscreen>
 
-/* Respond to a button-press by posting a menu passed in as widget.
- *
- * Note that the "widget" argument is the menu being posted, NOT
- * the button that was pressed.
- */
+Determine if a generic pointer refers to a `GtkTree' object
+<em>and</em> is a root tree. Though this will accept any pointer, the
+results of passing it a pointer that does not refer to a GtkTree are
+undefined and possibly harmful.
 
-static gint button_press (GtkWidget *widget, GdkEvent *event)
-{
+<tscreen><verb>
+GtkTree *GTK_TREE_ROOT_TREE (gpointer obj)
+</verb></tscreen>
 
-    if (event->type == GDK_BUTTON_PRESS) {
-        GdkEventButton *bevent = (GdkEventButton *) event; 
-        gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
-                        bevent->button, bevent->time);
-        /* Tell calling code that we have handled this event; the buck
-         * stops here. */
-        return TRUE;
-    }
+Return the root tree of a pointer to a `GtkTree' object. The above
+warning applies.
 
-    /* Tell calling code that we have not handled this event; pass it on. */
-    return FALSE;
-}
+<tscreen><verb>
+GList *GTK_TREE_SELECTION( gpointer obj)
+</verb></tscreen>
 
+Return the selection list of the root tree of a `GtkTree' object. The 
+above warning applies here, too.
 
-/* Print a string when a menu item is selected */
+<sect1> Tree Item Widget<label id="sec_Tree_Item_Widget">
+<p>
+The GtkTreeItem widget, like GtkListItem, is derived from GtkItem,
+which in turn is derived from GtkBin.  Therefore, the item itself is a
+generic container holding exactly one child widget, which can be of
+any type.  The GtkTreeItem widget has a number of extra fields, but
+the only one we need be concerned with is the <tt>subtree</tt> field.
 
-static void menuitem_response (gchar *string)
+The definition for the GtkTreeItem struct looks like this:
+
+<tscreen><verb>
+struct _GtkTreeItem
 {
-    printf("%s\n", string);
+  GtkItem item;
+
+  GtkWidget *subtree;
+  GtkWidget *pixmaps_box;
+  GtkWidget *plus_pix_widget, *minus_pix_widget;
+
+  GList *pixmaps;              /* pixmap node for this items color depth */
+
+  guint expanded : 1;
+};
+</verb></tscreen>
+
+The <tt>pixmaps_box</tt> field is a GtkEventBox which catches clicks
+on the plus/minus symbol which controls expansion and collapsing.  The
+<tt>pixmaps</tt> field points to an internal data structure.  Since
+you can always obtain the subtree of a GtkTreeItem in a (relatively)
+type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's
+probably advisable never to touch the insides of a GtkTreeItem unless
+you <em>really</em> know what you're doing.
+
+Since it is directly derived from a GtkItem it can be treated as such
+by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a
+label, so the convenience function gtk_list_item_new_with_label() is
+provided. The same effect can be achieved using code like the
+following, which is actually copied verbatim from
+gtk_tree_item_new_with_label():
+
+<tscreen><verb>
+tree_item = gtk_tree_item_new ();
+label_widget = gtk_label_new (label);
+gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5);
+
+gtk_container_add (GTK_CONTAINER (tree_item), label_widget);
+gtk_widget_show (label_widget);
+</verb></tscreen>
+
+As one is not forced to add a GtkLabel to a GtkTreeItem, you could
+also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your
+app will likely be quite unpopular in this case) to the GtkTreeItem.
+
+If you remove all the items from a subtree, it will be destroyed and
+unparented, unless you reference it beforehand, and the GtkTreeItem
+which owns it will be collapsed.  So, if you want it to stick around,
+do something like the following:
+
+<tscreen><verb>
+gtk_widget_ref (tree);
+owner = GTK_TREE(tree)->tree_owner;
+gtk_container_remove (GTK_CONTAINER(tree), item);
+if (tree->parent == NULL){
+  gtk_tree_item_expand (GTK_TREE_ITEM(owner));
+  gtk_tree_item_set_subtree (GTK_TREE_ITEM(owner), tree);
 }
-/* example-end */
+else
+  gtk_widget_unref (tree);
 </verb></tscreen>
 
-You may also set a menu item to be insensitive and, using an accelerator
-table, bind keys to menu functions.
+Finally, drag-n-drop <em>does</em> work with GtkTreeItems.  You just
+have to make sure that the GtkTreeItem you want to make into a drag
+item or a drop site has not only been added to a GtkTree, but that
+each successive parent widget has a parent itself, all the way back to
+a toplevel or dialog window, when you call gtk_widget_dnd_drag_set()
+or gtk_widget_dnd_drop_set().  Otherwise, strange things will happen.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Using GtkMenuFactory
+<sect2> Signals
 <p>
-Now that we've shown you the hard way, here's how you do it using the
-gtk_menu_factory calls.
+GtkTreeItem inherits the "select", "deselect", and "toggle" signals
+from GtkItem.  In addition, it adds two signals of its own, "expand"
+and "collapse".
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Menu Factory Example
+<tscreen><verb>
+void select( GtkItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when an item is about to be selected, either
+after it has been clicked on by the user, or when the program calls
+gtk_tree_item_select(), gtk_item_select(), or gtk_tree_select_child().
+
+<tscreen><verb>
+void deselect( GtkItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when an item is about to be unselected, either
+after it has been clicked on by the user, or when the program calls
+gtk_tree_item_deselect() or gtk_item_deselect(). In the case of
+GtkTreeItems, it is also emitted by gtk_tree_unselect_child(), and
+sometimes gtk_tree_select_child().
+
+<tscreen><verb>
+void toggle( GtkItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when the program calls gtk_item_toggle().  The
+effect it has when emitted on a GtkTreeItem is to call
+gtk_tree_select_child() (and never gtk_tree_unselect_child()) on the
+item's parent tree, if the item has a parent tree.  If it doesn't,
+then the highlight is reversed on the item.
+
+<tscreen><verb>
+void expand( GtkTreeItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when the tree item's subtree is about to be
+expanded, that is, when the user clicks on the plus sign next to the
+item, or when the program calls gtk_tree_item_expand().
+
+<tscreen><verb>
+void collapse( GtkTreeItem *tree_item );
+</verb></tscreen>
+
+This signal is emitted when the tree item's subtree is about to be
+collapsed, that is, when the user clicks on the minus sign next to the
+item, or when the program calls gtk_tree_item_collapse().
+
+<sect2> Functions and Macros
 <p>
-Here is an example using the GTK menu factory.  This is the first file,
-menufactory.h.  We keep a separate menufactory.c and mfmain.c because
-of the global variables used in the menufactory.c file.  
+<tscreen><verb>
+guint gtk_tree_item_get_type( void );
+</verb></tscreen>
+
+Returns the `GtkTreeItem' type identifier.
 
 <tscreen><verb>
-/* example-start menu menufactory.h */
+GtkWidget* gtk_tree_item_new( void );
+</verb></tscreen>
 
-#ifndef __MENUFACTORY_H__
-#define __MENUFACTORY_H__
+Create a new GtkTreeItem object. The new widget is returned as a pointer
+to a GtkWidget object. NULL is returned on failure.
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+<tscreen><verb>
+GtkWidget* gtk_tree_item_new_with_label (gchar       *label);
+</verb></tscreen>
 
-void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
-void menus_create(GtkMenuEntry *entries, int nmenu_entries);
+Create a new GtkTreeItem object, having a single GtkLabel as
+the sole child. The new widget is returned as a pointer to a
+GtkWidget object. NULL is returned on failure.
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+<tscreen><verb>
+void gtk_tree_item_select( GtkTreeItem *tree_item );
+</verb></tscreen>
 
-#endif /* __MENUFACTORY_H__ */
-/* example-end */
+This function is basicaly a wrapper around a call to
+gtk_item_select (GTK_ITEM (tree_item)) which will emit the
+select signal.
+
+<tscreen><verb>
+void gtk_tree_item_deselect( GtkTreeItem *tree_item );
 </verb></tscreen>
 
-And here is the menufactory.c file.
+This function is basicaly a wrapper around a call to
+gtk_item_deselect (GTK_ITEM (tree_item)) which will emit the
+deselect signal.
 
 <tscreen><verb>
-/* example-start menu menufactory.c */
+void gtk_tree_item_set_subtree( GtkTreeItem *tree_item,
+                                GtkWidget   *subtree );
+</verb></tscreen>
 
-#include <gtk/gtk.h>
-#include <strings.h>
+This function adds subtree to tree_item, showing it if tree_item is
+expanded, or hiding it if tree_item is collapsed. Again, remember
+that the tree_item must have already been added to a tree for this to
+work.
 
-#include "mfmain.h"
+<tscreen><verb>
+void gtk_tree_item_remove_subtree( GtkTreeItem *tree_item );
+</verb></tscreen>
 
+This removes all of tree_item's subtree's children (thus unreferencing
+and destroying it, any of its children's subtrees, and so on...), then
+removes the subtree itself, and hides the plus/minus sign.
 
-static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
-static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
-void menus_init(void);
-void menus_create(GtkMenuEntry * entries, int nmenu_entries);
+<tscreen><verb>
+void gtk_tree_item_expand( GtkTreeItem *tree_item );
+</verb></tscreen>
 
+This emits the "expand" signal on tree_item, which expands it.
 
-/* this is the GtkMenuEntry structure used to create new menus.  The
- * first member is the menu definition string.  The second, the
- * default accelerator key used to access this menu function with
- * the keyboard.  The third is the callback function to call when
- * this menu item is selected (by the accelerator key, or with the
- * mouse.) The last member is the data to pass to your callback function.
- */
+<tscreen><verb>
+void gtk_tree_item_collapse( GtkTreeItem *tree_item );
+</verb></tscreen>
 
-static GtkMenuEntry menu_items[] =
-{
-       {"<Main>/File/New", "<control>N", NULL, NULL},
-       {"<Main>/File/Open", "<control>O", NULL, NULL},
-       {"<Main>/File/Save", "<control>S", NULL, NULL},
-       {"<Main>/File/Save as", NULL, NULL, NULL},
-       {"<Main>/File/<separator>", NULL, NULL, NULL},
-       {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
-       {"<Main>/Options/Test", NULL, NULL, NULL}
-};
+This emits the "collapse" signal on tree_item, which collapses it.
 
-/* calculate the number of menu_item's */
-static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
+<tscreen><verb>
+GtkTreeItem *GTK_TREE_ITEM (gpointer obj)
+</verb></tscreen>
 
-static int initialize = TRUE;
-static GtkMenuFactory *factory = NULL;
-static GtkMenuFactory *subfactory[1];
-static GHashTable *entry_ht = NULL;
+Cast a generic pointer to `GtkTreeItem*'.
 
-void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
+<tscreen><verb>
+GtkTreeItemClass *GTK_TREE_ITEM_CLASS (gpointer obj)
+</verb></tscreen>
+
+Cast a generic pointer to `GtkTreeItemClass'.
+
+<tscreen><verb>
+gint GTK_IS_TREE_ITEM (gpointer obj)
+</verb></tscreen>
+
+Determine if a generic pointer refers to a `GtkTreeItem' object.
+<tscreen><verb>
+GtkWidget GTK_TREE_ITEM_SUBTREE (gpointer obj)
+</verb></tscreen>
+
+Return's a tree item's subtree (obj should point to a `GtkTreeItem'
+object).
+
+<sect1> Tree Example
+<p>
+This is somewhat like the tree example in testgtk.c, but a lot less
+complete (although much better commented).  It puts up a window with a
+tree, and connects all the signals for the relevant objects, so you
+can see when they are emitted.
+
+<tscreen><verb>
+/* example-start tree tree.c */
+
+#include <gtk/gtk.h>
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal (GtkWidget *item, gchar *signame)
 {
-    if (initialize)
-           menus_init();
-    
-    if (menubar)
-           *menubar = subfactory[0]->widget;
-    if (table)
-           *table = subfactory[0]->table;
+  gchar *name;
+  GtkLabel *label;
+
+  /* It's a GtkBin, so it has one child, which we know to be a
+     label, so get that */
+  label = GTK_LABEL (GTK_BIN (item)->child);
+  /* Get the text of the label */
+  gtk_label_get (label, &amp;name);
+  /* Get the level of the tree which the item is in */
+  g_print ("%s called for item %s->%p, level %d\n", signame, name,
+          item, GTK_TREE (item->parent)->level);
 }
 
-void menus_init(void)
+/* Note that this is never called */
+static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
+                              GtkWidget *subtree)
 {
-    if (initialize) {
-       initialize = FALSE;
-       
-       factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
-       subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
-       
-       gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
-       menus_create(menu_items, nmenu_items);
-    }
+  g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
 }
 
-void menus_create(GtkMenuEntry * entries, int nmenu_entries)
+/* Note that this is called every time the user clicks on an item,
+   whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+                            GtkWidget *subtree)
 {
-    char *accelerator;
-    int i;
-    
-    if (initialize)
-           menus_init();
-    
-    if (entry_ht)
-           for (i = 0; i < nmenu_entries; i++) {
-               accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
-               if (accelerator) {
-                   if (accelerator[0] == '\0')
-                           entries[i].accelerator = NULL;
-                   else
-                           entries[i].accelerator = accelerator;
-               }
-           }
-    gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
-    
-    for (i = 0; i < nmenu_entries; i++)
-           if (entries[i].widget) {
-               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
-                                  (GtkSignalFunc) menus_install_accel,
-                                  entries[i].path);
-               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
-                                  (GtkSignalFunc) menus_remove_accel,
-                                  entries[i].path);
-           }
+  g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
 }
 
-static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
+static void cb_selection_changed (GtkWidget *tree)
 {
-    char accel[64];
-    char *t1, t2[2];
-    
-    accel[0] = '\0';
-    if (modifiers & GDK_CONTROL_MASK)
-           strcat(accel, "<control>");
-    if (modifiers & GDK_SHIFT_MASK)
-           strcat(accel, "<shift>");
-    if (modifiers & GDK_MOD1_MASK)
-           strcat(accel, "<alt>");
-    
-    t2[0] = key;
-    t2[1] = '\0';
-    strcat(accel, t2);
-    
-    if (entry_ht) {
-       t1 = g_hash_table_lookup(entry_ht, path);
-       g_free(t1);
-    } else
-           entry_ht = g_hash_table_new(g_str_hash, g_str_equal);
-    
-    g_hash_table_insert(entry_ht, path, g_strdup(accel));
-    
-    return TRUE;
+  GList *i;
+  
+  g_print ("selection_change called for tree %p\n", tree);
+  g_print ("selected objects are:\n");
+
+  i = GTK_TREE_SELECTION(tree);
+  while (i){
+    gchar *name;
+    GtkLabel *label;
+    GtkWidget *item;
+
+    /* Get a GtkWidget pointer from the list node */
+    item = GTK_WIDGET (i->data);
+    label = GTK_LABEL (GTK_BIN (item)->child);
+    gtk_label_get (label, &amp;name);
+    g_print ("\t%s on level %d\n", name, GTK_TREE
+            (item->parent)->level);
+    i = i->next;
+  }
 }
 
-static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
+int main (int argc, char *argv[])
 {
-    char *t;
-    
-    if (entry_ht) {
-       t = g_hash_table_lookup(entry_ht, path);
-       g_free(t);
-       
-       g_hash_table_insert(entry_ht, path, g_strdup(""));
+  GtkWidget *window, *scrolled_win, *tree;
+  static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
+                              "Maurice"};
+  gint i;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  /* a generic toplevel window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+  gtk_container_border_width (GTK_CONTAINER(window), 5);
+
+  /* A generic scrolled window */
+  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_widget_set_usize (scrolled_win, 150, 200);
+  gtk_container_add (GTK_CONTAINER(window), scrolled_win);
+  gtk_widget_show (scrolled_win);
+  
+  /* Create the root tree */
+  tree = gtk_tree_new();
+  g_print ("root tree is %p\n", tree);
+  /* connect all GtkTree:: signals */
+  gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+                     GTK_SIGNAL_FUNC(cb_select_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+                     GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+                     GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+  /* Add it to the scrolled window */
+  gtk_container_add (GTK_CONTAINER(scrolled_win), tree);
+  /* Set the selection mode */
+  gtk_tree_set_selection_mode (GTK_TREE(tree),
+                              GTK_SELECTION_MULTIPLE);
+  /* Show it */
+  gtk_widget_show (tree);
+
+  for (i = 0; i < 5; i++){
+    GtkWidget *subtree, *item;
+    gint j;
+
+    /* Create a tree item */
+    item = gtk_tree_item_new_with_label (itemnames[i]);
+    /* Connect all GtkItem:: and GtkTreeItem:: signals */
+    gtk_signal_connect (GTK_OBJECT(item), "select",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+    gtk_signal_connect (GTK_OBJECT(item), "deselect",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+    gtk_signal_connect (GTK_OBJECT(item), "toggle",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+    gtk_signal_connect (GTK_OBJECT(item), "expand",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+    gtk_signal_connect (GTK_OBJECT(item), "collapse",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+    /* Add it to the parent tree */
+    gtk_tree_append (GTK_TREE(tree), item);
+    /* Show it - this can be done at any time */
+    gtk_widget_show (item);
+    /* Create this item's subtree */
+    subtree = gtk_tree_new();
+    g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
+            subtree);
+
+    /* This is still necesary if you want these signals to be called
+       for the subtree's children.  Note that selection_change will be 
+       signalled for the root tree regardless. */
+    gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+                       GTK_SIGNAL_FUNC(cb_select_child), subtree);
+    gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+                       GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
+    /* This has absolutely no effect, because it is completely ignored 
+       in subtrees */
+    gtk_tree_set_selection_mode (GTK_TREE(subtree),
+                                GTK_SELECTION_SINGLE);
+    /* Neither does this, but for a rather different reason - the
+       view_mode and view_line values of a tree are propagated to
+       subtrees when they are mapped.  So, setting it later on would
+       actually have a (somewhat unpredictable) effect */
+    gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
+    /* Set this item's subtree - note that you cannot do this until
+       AFTER the item has been added to its parent tree! */
+    gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
+
+    for (j = 0; j < 5; j++){
+      GtkWidget *subitem;
+
+      /* Create a subtree item, in much the same way */
+      subitem = gtk_tree_item_new_with_label (itemnames[j]);
+      /* Connect all GtkItem:: and GtkTreeItem:: signals */
+      gtk_signal_connect (GTK_OBJECT(subitem), "select",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+      gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+      gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+      gtk_signal_connect (GTK_OBJECT(subitem), "expand",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+      gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+      g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
+      /* Add it to its parent tree */
+      gtk_tree_append (GTK_TREE(subtree), subitem);
+      /* Show it */
+      gtk_widget_show (subitem);
     }
-}
+  }
 
-void menus_set_sensitive(char *path, int sensitive)
-{
-    GtkMenuPath *menu_path;
-    
-    if (initialize)
-           menus_init();
-    
-    menu_path = gtk_menu_factory_find(factory, path);
-    if (menu_path)
-           gtk_widget_set_sensitive(menu_path->widget, sensitive);
-    else
-           g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path);
+  /* Show the window and loop endlessly */
+  gtk_widget_show (window);
+  gtk_main();
+  return 0;
 }
 /* example-end */
 </verb></tscreen>
 
-And here's the mfmain.h
-
-<tscreen><verb>
-/* example-start menu mfmain.h */
+<!-- ***************************************************************** -->
+<sect>Menu Widget
+<!-- ***************************************************************** -->
+<p>
+There are two ways to create menus, there's the easy way, and there's the
+hard way. Both have their uses, but you can usually use the menufactory
+(the easy way). The "hard" way is to create all the menus using the calls
+directly. The easy way is to use the gtk_menu_factory calls. This is
+much simpler, but there are advantages and disadvantages to each approach.
 
-#ifndef __MFMAIN_H__
-#define __MFMAIN_H__
+The menufactory is much easier to use, and to add new menus to, although
+writing a few wrapper functions to create menus using the manual method 
+could go a long way towards usability. With the menufactory, it is not 
+possible to add images or the character '/' to the menus.
 
+<!-- ----------------------------------------------------------------- -->
+<sect1>Manual Menu Creation
+<p>
+In the true tradition of teaching, we'll show you the hard
+way first. <tt>:)</>
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+There are three widgets that go into making a menubar and submenus:
+<itemize>
+<item>a menu item, which is what the user wants to select, e.g. 'Save'
+<item>a menu, which acts as a container for the menu items, and
+<item>a menubar, which is a container for each of the individual menus,
+</itemize>
 
-void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
+This is slightly complicated by the fact that menu item widgets are used
+for two different things. They are both the widets that are packed into
+the menu, and the widget that is packed into the menubar, which,
+when selected, activiates the menu.
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+Let's look at the functions that are used to create menus and menubars.
+This first function is used to create a new menubar.
 
-#endif /* __MFMAIN_H__ */
-/* example-end */
+<tscreen><verb>
+GtkWidget *gtk_menu_bar_new( void );
 </verb></tscreen>
 
-And mfmain.c
+This rather self explanatory function creates a new menubar.  You use
+gtk_container_add to pack this into a window, or the box_pack functions to
+pack it into a box - the same as buttons.
 
 <tscreen><verb>
-/* example-start menu mfmain.c */
-
-#include <gtk/gtk.h>
-
-#include "mfmain.h"
-#include "menufactory.h"
+GtkWidget *gtk_menu_new( void );
+</verb></tscreen>
 
+This function returns a pointer to a new menu, it is never actually shown
+(with gtk_widget_show), it is just a container for the menu items.  Hopefully this will
+become more clear when you look at the example below.
 
-int main(int argc, char *argv[])
-{
-    GtkWidget *window;
-    GtkWidget *main_vbox;
-    GtkWidget *menubar;
-    
-    GtkAcceleratorTable *accel;
-    
-    gtk_init(&amp;argc, &amp;argv);
-    
-    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
-    gtk_signal_connect(GTK_OBJECT(window), "destroy", 
-                      GTK_SIGNAL_FUNC(file_quit_cmd_callback), 
-                      "WM destroy");
-    gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
-    gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
-    
-    main_vbox = gtk_vbox_new(FALSE, 1);
-    gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
-    gtk_container_add(GTK_CONTAINER(window), main_vbox);
-    gtk_widget_show(main_vbox);
-    
-    get_main_menu(&amp;menubar, &amp;accel);
-    gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
-    gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
-    gtk_widget_show(menubar);
-    
-    gtk_widget_show(window);
-    gtk_main();
-    
-    return(0);
-}
+The next two calls are used to create menu items that are packed into
+the menu (and menubar).
 
-/* This is just to demonstrate how callbacks work when using the
- * menufactory.  Often, people put all the callbacks from the menus
- * in a separate file, and then have them call the appropriate functions
- * from there.  Keeps it more organized. */
-void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
-{
-    g_print ("%s\n", (char *) data);
-    gtk_exit(0);
-}
-/* example-end */
+<tscreen><verb>
+GtkWidget *gtk_menu_item_new( void );
 </verb></tscreen>
 
-And a makefile so it'll be easier to compile it.
+and
 
 <tscreen><verb>
-# Makefile.mf
+GtkWidget *gtk_menu_item_new_with_label( const char *label );
+</verb></tscreen>
 
-CC      = gcc
-PROF    = -g
-C_FLAGS =  -Wall $(PROF) -L/usr/local/include -DDEBUG
-L_FLAGS =  $(PROF) -L/usr/X11R6/lib -L/usr/local/lib 
-L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
-PROGNAME = menufactory
+These calls are used to create the menu items that are to be displayed.
+Remember to differentiate between a "menu" as created with gtk_menu_new
+and a "menu item" as created by the gtk_menu_item_new functions. The
+menu item will be an actual button with an associated action,
+whereas a menu will be a container holding menu items.
 
-O_FILES = menufactory.o mfmain.o
+The gtk_menu_new_with_label and gtk_menu_new functions are just as you'd expect after
+reading about the buttons. One creates a new menu item with a label
+already packed into it, and the other just creates a blank menu item.
 
-$(PROGNAME): $(O_FILES)
-       rm -f $(PROGNAME)
-       $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
+Once you've created a menu item you have to put it into a menu. This is 
+done using the function gtk_menu_append. In order to capture when the item
+is selected by the user, we need to connect to the <tt/activate/ signal in
+the usual way. So, if we wanted to create a standard <tt/File/ menu, with
+the options <tt/Open/, <tt/Save/ and <tt/Quit/ the code would look something like
 
-.c.o: 
-       $(CC) -c $(C_FLAGS) $<
+<tscreen><verb>
+file_menu = gtk_menu_new();    /* Don't need to show menus */
 
-clean: 
-       rm -f core *.o $(PROGNAME) nohup.out
-distclean: clean 
-       rm -f *~
-</verb></tscreen>
+/* Create the menu items */
+open_item = gtk_menu_item_new_with_label("Open");
+save_item = gtk_menu_item_new_with_label("Save");
+quit_item = gtk_menu_item_new_with_label("Quit");
 
-For now, there's only this example.  An explanation and lots 'o' comments
-will follow later.
+/* Add them to the menu */
+gtk_menu_append( GTK_MENU(file_menu), open_item);
+gtk_menu_append( GTK_MENU(file_menu), save_item);
+gtk_menu_append( GTK_MENU(file_menu), quit_item);
 
-<!-- ***************************************************************** -->
-<sect> Text Widget
-<!-- ***************************************************************** -->
-<p>
-The Text widget allows multiple lines of text to be displayed and edited.
-It supports both multi-colored and multi-font text, allowing them to be
-mixed in any way we wish. It also has a wide set of key based text editing
-commands, which are compatible with Emacs.
+/* Attach the callback functions to the activate signal */
+gtk_signal_connect_object( GTK_OBJECT(open_items), "activate",
+                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.open");
+gtk_signal_connect_object( GTK_OBJECT(save_items), "activate",
+                          GTK_SIGNAL_FUNC(menuitem_response), (gpointer) "file.save");
 
-The text widget supports full cut-and-paste facilities, including the use
-of double- and triple-click to select a word and a whole line, respectively.
+/* We can attach the Quit menu item to our exit function */
+gtk_signal_connect_object( GTK_OBJECT(quit_items), "activate",
+                          GTK_SIGNAL_FUNC(destroy), (gpointer) "file.quit");
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Creating and Configuring a Text box
-<p>
-There is only one function for creating a new Text widget.
-<tscreen><verb>
-GtkWidget *gtk_text_new( GtkAdjustment *hadj,
-                         GtkAdjustment *vadj );
+/* We do need to show menu items */
+gtk_widget_show( open_item );
+gtk_widget_show( save_item );
+gtk_widget_show( quit_item );
 </verb></tscreen>
 
-The arguments allow us to give the Text widget pointers to Adjustments
-that can be used to track the viewing position of the widget. Passing NULL
-values to either or both of these arguments will cause the gtk_text_new
-function to create it's own.
+At this point we have our menu. Now we need to create a menubar and a menu
+item for the <tt/File/ entry, to which we add our menu. The code looks like this 
 
 <tscreen><verb>
-void gtk_text_set_adjustments( GtkText       *text,
-                               GtkAdjustment *hadj,
-                               GtkAdjustment *vadj );
+menu_bar = gtk_menu_bar_new();
+gtk_container_add( GTK_CONTAINER(window), menu_bar);
+gtk_widget_show( menu_bar );
+
+file_item = gtk_menu_item_new_with_label("File");
+gtk_widget_show(file_item);
 </verb></tscreen>
 
-The above function allows the horizontal and vertical adjustments of a
-Text widget to be changed at any time.
+Now we need to associate the menu with <tt/file_item/. This is done with the
+function
 
-The text widget will not automatically create it's own scrollbars when
-the amount of text to be displayed is too long for the display window. We
-therefore have to create and add them to the display layout ourselves.
+<tscreen>
+void gtk_menu_item_set_submenu( GtkMenuItem *menu_item,
+                                GtkWidget   *submenu );
+</tscreen>
+
+So, our example would continue with
 
 <tscreen><verb>
-  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
-  gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
-  gtk_widget_show (vscrollbar);
+gtk_menu_item_set_submenu( GTK_MENU_ITEM(file_item), file_menu );
 </verb></tscreen>
 
-The above code snippet creates a new vertical scrollbar, and attaches
-it to the vertical adjustment of the text widget, <tt/text/. It then packs
-it into a box in the normal way.
+All that is left to do is to add the menu to the menubar, which is accomplished
+using the function
 
-Note, currently the GtkText widget does not support horizontal scrollbars.
+<tscreen>
+void gtk_menu_bar_append( GtkMenuBar *menu_bar, GtkWidget *menu_item);
+</tscreen>
 
-There are two main ways in which a Text widget can be used: to allow the
-user to edit a body of text, or to allow us to display multiple lines of
-text to the user. In order for us to switch between these modes of
-operation, the text widget has the following function:
+which in our case looks like this:
 
 <tscreen><verb>
-void gtk_text_set_editable( GtkText *text,
-                            gint     editable );
+gtk_menu_bar_append( GTK_MENU_BAR (menu_bar), file_item );
 </verb></tscreen>
 
-The <tt/editable/ argument is a TRUE or FALSE value that specifies whether
-the user is permitted to edit the contents of the Text widget. When the
-text widget is editable, it will display a cursor at the current insertion
-point.
-
-You are not, however, restricted to just using the text widget in these
-two modes. You can toggle the editable state of the text widget at any
-time, and can insert text at any time.
-
-The text widget wraps lines of text that are too long to
-fit onto a single line of the display window. It's default behaviour is
-to break words across line breaks. This can be changed using the next
-function:
+If we wanted the menu right justified on the menubar, such as help menus
+often are, we can use the following function (again on <tt/file_item/
+in the current example) before attaching it to the menubar.
 
 <tscreen><verb>
-void gtk_text_set_word_wrap( GtkText *text,
-                             gint     word_wrap );
+void gtk_menu_item_right_justify( GtkMenuItem *menu_item );
 </verb></tscreen>
 
-Using this function allows us to specify that the text widget should
-wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
-TRUE or FALSE value.
+Here is a summary of the steps needed to create a menu bar with menus attached:
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Text Manipulation
-<P>
-The current insertion point of a Text widget can be set using
-<tscreen><verb>
-void gtk_text_set_point( GtkText *text,
-                         guint    index );
-</verb></tscreen>
+<itemize>
+<item> Create a new menu using gtk_menu_new()
+<item> Use multiple calls to gtk_menu_item_new() for each item you wish to have
+on your menu. And use gtk_menu_append() to put each of these new items on 
+to the menu.
+<item> Create a menu item using gtk_menu_item_new(). This will be the root of
+the menu, the text appearing here will be on the menubar itself.
+<item>Use gtk_menu_item_set_submenu() to attach the menu to the root menu 
+item (the one created in the above step).
+<item> Create a new menubar using gtk_menu_bar_new. This step only needs
+to be done once when creating a series of menus on one menu bar.
+<item> Use gtk_menu_bar_append to put the root menu onto the menubar.
+</itemize>
 
-where <tt/index/ is the position to set the insertion point.
+Creating a popup menu is nearly the same. The difference is that the
+menu is not posted `automatically' by a menubar, but explicitly by calling
+the function gtk_menu_popup() from a button-press event, for example.
+Take these steps:
 
-Analogous to this is the function for getting the current insertion point:
+<itemize>
+<item>Create an event handling function. It needs to have the prototype
+<tscreen>
+static gint handler( GtkWidget *widget,
+                     GdkEvent  *event );
+</tscreen>
+and it will use the event to find out where to pop up the menu.
+<item>In the event handler, if the event is a mouse button press, treat
+<tt>event</tt> as a button event (which it is) and use it as
+shown in the sample code to pass information to gtk_menu_popup().
+<item>Bind that event handler to a widget with
+<tscreen>
+gtk_signal_connect_object(GTK_OBJECT(widget), "event",
+                          GTK_SIGNAL_FUNC (handler), GTK_OBJECT(menu));
+</tscreen>
+where <tt>widget</tt> is the widget you are binding to, <tt>handler</tt>
+is the handling function, and <tt>menu</tt> is a menu created with
+gtk_menu_new().  This can be a menu which is also posted by a menu bar,
+as shown in the sample code.
+</itemize>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Manual Menu Example
+<p>
+That should about do it.  Let's take a look at an example to help clarify.
 
 <tscreen><verb>
-guint gtk_text_get_point( GtkText *text );
-</verb></tscreen>
+/* example-start menu menu.c */
 
-A function that is useful in combination with the above two functions is
+#include <gtk/gtk.h>
 
-<tscreen><verb>
-guint gtk_text_get_length( GtkText *text );
-</verb></tscreen>
+static gint button_press (GtkWidget *, GdkEvent *);
+static void menuitem_response (gchar *);
 
-which returns the current length of the Text widget. The length is the
-number of characters that are within the text block of the widget,
-including characters such as carriage-return, which marks the end of lines.
+int main (int argc, char *argv[])
+{
 
-In order to insert text at the current insertion point of a Text
-widget, the function gtk_text_insert is used, which also allows us to
-specify background and foreground colors and a font for the text.
+    GtkWidget *window;
+    GtkWidget *menu;
+    GtkWidget *menu_bar;
+    GtkWidget *root_menu;
+    GtkWidget *menu_items;
+    GtkWidget *vbox;
+    GtkWidget *button;
+    char buf[128];
+    int i;
 
-<tscreen><verb>
-void gtk_text_insert( GtkText    *text,
-                      GdkFont    *font,
-                      GdkColor   *fore,
-                      GdkColor   *back,
-                      const char *chars,
-                      gint        length );
-</verb></tscreen>
+    gtk_init (&amp;argc, &amp;argv);
 
-Passing a value of <tt/NULL/ in as the value for the foreground color,
-background colour or font will result in the values set within the widget
-style to be used. Using a value of <tt/-1/ for the length parameter will
-result in the whole of the text string given being inserted.
+    /* create a new window */
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_widget_set_usize( GTK_WIDGET (window), 200, 100);
+    gtk_window_set_title(GTK_WINDOW (window), "GTK Menu Test");
+    gtk_signal_connect(GTK_OBJECT (window), "delete_event",
+                       (GtkSignalFunc) gtk_main_quit, NULL);
 
-The text widget is one of the few within GTK that redraws itself
-dynamically, outside of the gtk_main function. This means that all changes
-to the contents of the text widget take effect immediately. This may be
-undesirable when performing multiple changes to the text widget. In order
-to allow us to perform multiple updates to the text widget without it
-continuously redrawing, we can freeze the widget, which temporarily stops
-it from automatically redrawing itself every time it is changed. We can
-then thaw the widget after our updates are complete.
+    /* Init the menu-widget, and remember -- never
+     * gtk_show_widget() the menu widget!! 
+     * This is the menu that holds the menu items, the one that
+     * will pop up when you click on the "Root Menu" in the app */
+    menu = gtk_menu_new();
 
-The following two functions perform this freeze and thaw action:
+    /* Next we make a little loop that makes three menu-entries for "test-menu".
+     * Notice the call to gtk_menu_append.  Here we are adding a list of
+     * menu items to our menu.  Normally, we'd also catch the "clicked"
+     * signal on each of the menu items and setup a callback for it,
+     * but it's omitted here to save space. */
 
-<tscreen><verb>
-void gtk_text_freeze( GtkText *text );
+    for(i = 0; i < 3; i++)
+        {
+            /* Copy the names to the buf. */
+            sprintf(buf, "Test-undermenu - %d", i);
 
-void gtk_text_thaw( GtkText *text );         
-</verb></tscreen>
+            /* Create a new menu-item with a name... */
+            menu_items = gtk_menu_item_new_with_label(buf);
 
-Text is deleted from the text widget relative to the current insertion
-point by the following two functions. The return value is a TRUE or
-FALSE indicator of whether the operation was successful.
+            /* ...and add it to the menu. */
+            gtk_menu_append(GTK_MENU (menu), menu_items);
 
-<tscreen><verb>
-gint gtk_text_backward_delete( GtkText *text,
-                               guint    nchars );
+           /* Do something interesting when the menuitem is selected */
+           gtk_signal_connect_object(GTK_OBJECT(menu_items), "activate",
+               GTK_SIGNAL_FUNC(menuitem_response), (gpointer) g_strdup(buf));
 
-gint gtk_text_forward_delete ( GtkText *text,
-                               guint    nchars );
-</verb></tscreen>
+            /* Show the widget */
+            gtk_widget_show(menu_items);
+        }
 
-If you want to retrieve the contents of the text widget, then the macro 
-<tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the character at
-position <tt/index/ within the text widget <tt/t/.
+    /* This is the root menu, and will be the label
+     * displayed on the menu bar.  There won't be a signal handler attached,
+     * as it only pops up the rest of the menu when pressed. */
+    root_menu = gtk_menu_item_new_with_label("Root Menu");
 
-To retrieve larger blocks of text, we can use the function
+    gtk_widget_show(root_menu);
 
-<tscreen><verb>
-gchar *gtk_editable_get_chars( GtkEditable *editable,
-                               gint         start_pos,
-                               gint         end_pos );   
-</verb></tscreen>
+    /* Now we specify that we want our newly created "menu" to be the menu
+     * for the "root menu" */
+    gtk_menu_item_set_submenu(GTK_MENU_ITEM (root_menu), menu);
 
-This is a function of the parent class of the text widget. A value of -1 as
-<tt/end_pos/ signifies the end of the text. The index of the text starts at 0.
+    /* A vbox to put a menu and a button in: */
+    vbox = gtk_vbox_new(FALSE, 0);
+    gtk_container_add(GTK_CONTAINER(window), vbox);
+    gtk_widget_show(vbox);
 
-The function allocates a new chunk of memory for the text block, so don't forget
-to free it with a call to g_free when you have finished with it.
-<!-- ----------------------------------------------------------------- -->
-<sect1>Keyboard Shortcuts
-<p>
-The text widget has a number of pre-installed keyboard shotcuts for common
-editing, motion and selection functions. These are accessed using Control
-and Alt key combinations.
+    /* Create a menu-bar to hold the menus and add it to our main window */
+    menu_bar = gtk_menu_bar_new();
+    gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, FALSE, 2);
+    gtk_widget_show(menu_bar);
 
-In addition to these, holding down the Control key whilst using cursor key
-movement will move the cursor by words rather than characters. Holding down
-Shift whilst using cursor movement will extend the selection.
+    /* Create a button to which to attach menu as a popup */
+    button = gtk_button_new_with_label("press me");
+    gtk_signal_connect_object(GTK_OBJECT(button), "event",
+       GTK_SIGNAL_FUNC (button_press), GTK_OBJECT(menu));
+    gtk_box_pack_end(GTK_BOX(vbox), button, TRUE, TRUE, 2);
+    gtk_widget_show(button);
 
-<sect2>Motion Shotcuts
-<p>
-<itemize>
-<item> Ctrl-A   Beginning of line
-<item> Ctrl-E   End of line
-<item> Ctrl-N   Next Line
-<item> Ctrl-P   Previous Line
-<item> Ctrl-B   Backward one character
-<item> Ctrl-F   Forward one character
-<item> Alt-B    Backward one word
-<item> Alt-F    Forward one word
-</itemize>
+    /* And finally we append the menu-item to the menu-bar -- this is the
+     * "root" menu-item I have been raving about =) */
+    gtk_menu_bar_append(GTK_MENU_BAR (menu_bar), root_menu);
 
-<sect2>Editing Shortcuts
-<p>
-<itemize>
-<item> Ctrl-H   Delete Backward Character (Backspace)
-<item> Ctrl-D   Delete Forward Character (Delete)
-<item> Ctrl-W   Delete Backward Word
-<item> Alt-D    Delete Forward Word
-<item> Ctrl-K   Delete to end of line
-<item> Ctrl-U   Delete line
-</itemize>
+    /* always display the window as the last step so it all splashes on
+     * the screen at once. */
+    gtk_widget_show(window);
 
-<sect2>Selection Shortcuts
-<p>
-<itemize>
-<item> Ctrl-X   Cut to clipboard
-<item> Ctrl-C   Copy to clipboard
-<item> Ctrl-V   Paste from clipboard
-</itemize>
+    gtk_main ();
 
-<!-- ***************************************************************** -->
-<sect> Undocumented Widgets
-<!-- ***************************************************************** -->
-<p>
-These all require authors! :)  Please consider contributing to our tutorial.
+    return 0;
+}
 
-If you must use one of these widgets that are undocumented, I strongly
-suggest you take a look at their respective header files in the GTK
-distribution. GTK's function names are very descriptive.  Once you have an
-understanding of how things work, it's not difficult to figure out how to
-use a widget simply by looking at it's function declarations.  This, along
-with a few examples from others' code, and it should be no problem.
+/* Respond to a button-press by posting a menu passed in as widget.
+ *
+ * Note that the "widget" argument is the menu being posted, NOT
+ * the button that was pressed.
+ */
 
-When you do come to understand all the functions of a new undocumented
-widget, please consider writing a tutorial on it so others may benifit
-from your time.
+static gint button_press (GtkWidget *widget, GdkEvent *event)
+{
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Adjustments
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Toolbar
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Fixed Container
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Range Controls
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Curves
-<p>
-<!-- ----------------------------------------------------------------- -->
-<sect1> Previews
-<p>
+    if (event->type == GDK_BUTTON_PRESS) {
+        GdkEventButton *bevent = (GdkEventButton *) event; 
+        gtk_menu_popup (GTK_MENU(widget), NULL, NULL, NULL, NULL,
+                        bevent->button, bevent->time);
+        /* Tell calling code that we have handled this event; the buck
+         * stops here. */
+        return TRUE;
+    }
 
-(This may need to be rewritten to follow the style of the rest of the tutorial)
+    /* Tell calling code that we have not handled this event; pass it on. */
+    return FALSE;
+}
 
-<tscreen><verb>
 
-Previews serve a number of purposes in GIMP/GTK. The most important one is
-this. High quality images may take up to tens of megabytes of memory - easy!
-Any operation on an image that big is bound to take a long time. If it takes
-you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
-you make an error) to choose the desired modification, it make take you
-literally hours to make the right one - if you don't run out of memory
-first. People who have spent hours in color darkrooms know the feeling.
-Previews to the rescue!
+/* Print a string when a menu item is selected */
 
-But the annoyance of the delay is not the only issue. Oftentimes it is
-helpful to compare the Before and After versions side-by-side or at least
-back-to-back. If you're working with big images and 10 second delays,
-obtaining the Before and After impressions is, to say the least, difficult.
-For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
-out for most people, while back-to-back is more like back-to-1001, 1002,
-..., 1010-back! Previews to the rescue!
+static void menuitem_response (gchar *string)
+{
+    printf("%s\n", string);
+}
+/* example-end */
+</verb></tscreen>
 
-But there's more. Previews allow for side-by-side pre-previews. In other
-words, you write a plug-in (e.g. the filterpack simulation) which would have
-a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
-An approach like this acts as a sort of a preview palette and is very
-effective fow subtle changes. Let's go previews!
+You may also set a menu item to be insensitive and, using an accelerator
+table, bind keys to menu functions.
 
-There's more. For certain plug-ins real-time image-specific human
-intervention maybe necessary. In the SuperNova plug-in, for example, the
-user is asked to enter the coordinates of the center of the future
-supernova. The easiest way to do this, really, is to present the user with a
-preview and ask him to intereactively select the spot. Let's go previews!
+<!-- ----------------------------------------------------------------- -->
+<sect1>Using GtkMenuFactory
+<p>
+Now that we've shown you the hard way, here's how you do it using the
+gtk_menu_factory calls.
 
-Finally, a couple of misc uses. One can use previews even when not working
-with big images. For example, they are useful when rendering compicated
-patterns. (Just check out the venerable Diffraction plug-in + many other
-ones!) As another example, take a look at the colormap rotation plug-in
-(work in progress). You can also use previews for little logo's inside you
-plug-ins and even for an image of yourself, The Author. Let's go previews!
+<!-- ----------------------------------------------------------------- -->
+<sect1>Menu Factory Example
+<p>
+Here is an example using the GTK menu factory.  This is the first file,
+menufactory.h.  We keep a separate menufactory.c and mfmain.c because
+of the global variables used in the menufactory.c file.  
 
-When Not to Use Previews
+<tscreen><verb>
+/* example-start menu menufactory.h */
 
-Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
-previews only for rendered images!
+#ifndef __MENUFACTORY_H__
+#define __MENUFACTORY_H__
 
-Let's go previews!
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
-You can stick a preview into just about anything. In a vbox, an hbox, a
-table, a button, etc. But they look their best in tight frames around them.
-Previews by themselves do not have borders and look flat without them. (Of
-course, if the flat look is what you want...) Tight frames provide the
-necessary borders.
+void get_main_menu (GtkWidget **menubar, GtkAcceleratorTable **table);
+void menus_create(GtkMenuEntry *entries, int nmenu_entries);
 
-                               [Image][Image]
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-Previews in many ways are like any other widgets in GTK (whatever that
-means) except they possess an addtional feature: they need to be filled with
-some sort of an image! First, we will deal exclusively with the GTK aspect
-of previews and then we'll discuss how to fill them.
+#endif /* __MENUFACTORY_H__ */
+/* example-end */
+</verb></tscreen>
 
-GtkWidget *preview!
+And here is the menufactory.c file.
 
-Without any ado:
+<tscreen><verb>
+/* example-start menu menufactory.c */
 
-                              /* Create a preview widget,
-                              set its size, an show it */
-GtkWidget *preview;
-preview=gtk_preview_new(GTK_PREVIEW_COLOR)
-                              /*Other option:
-                              GTK_PREVIEW_GRAYSCALE);*/
-gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
-gtk_widget_show(preview);
-my_preview_rendering_function(preview);
+#include <gtk/gtk.h>
+#include <strings.h>
 
-Oh yeah, like I said, previews look good inside frames, so how about:
+#include "mfmain.h"
 
-GtkWidget *create_a_preview(int        Width,
-                            int        Height,
-                            int        Colorfulness)
-{
-  GtkWidget *preview;
-  GtkWidget *frame;
-  
-  frame = gtk_frame_new(NULL);
-  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
-  gtk_container_border_width (GTK_CONTAINER(frame),0);
-  gtk_widget_show(frame);
 
-  preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
-                                       :GTK_PREVIEW_GRAYSCALE);
-  gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
-  gtk_container_add(GTK_CONTAINER(frame),preview);
-  gtk_widget_show(preview);
+static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path);
+static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path);
+void menus_init(void);
+void menus_create(GtkMenuEntry * entries, int nmenu_entries);
 
-  my_preview_rendering_function(preview);
-  return frame;
-}
 
-That's my basic preview. This routine returns the "parent" frame so you can
-place it somewhere else in your interface. Of course, you can pass the
-parent frame to this routine as a parameter. In many situations, however,
-the contents of the preview are changed continually by your application. In
-this case you may want to pass a pointer to the preview to a
-"create_a_preview()" and thus have control of it later.
+/* this is the GtkMenuEntry structure used to create new menus.  The
+ * first member is the menu definition string.  The second, the
+ * default accelerator key used to access this menu function with
+ * the keyboard.  The third is the callback function to call when
+ * this menu item is selected (by the accelerator key, or with the
+ * mouse.) The last member is the data to pass to your callback function.
+ */
 
-One more important note that may one day save you a lot of time. Sometimes
-it is desirable to label you preview. For example, you may label the preview
-containing the original image as "Original" and the one containing the
-modified image as "Less Original". It might occure to you to pack the
-preview along with the appropriate label into a vbox. The unexpected caveat
-is that if the label is wider than the preview (which may happen for a
-variety of reasons unforseeable to you, from the dynamic decision on the
-size of the preview to the size of the font) the frame expands and no longer
-fits tightly over the preview. The same problem can probably arise in other
-situations as well.
+static GtkMenuEntry menu_items[] =
+{
+       {"<Main>/File/New", "<control>N", NULL, NULL},
+       {"<Main>/File/Open", "<control>O", NULL, NULL},
+       {"<Main>/File/Save", "<control>S", NULL, NULL},
+       {"<Main>/File/Save as", NULL, NULL, NULL},
+       {"<Main>/File/<separator>", NULL, NULL, NULL},
+       {"<Main>/File/Quit", "<control>Q", file_quit_cmd_callback, "OK, I'll quit"},
+       {"<Main>/Options/Test", NULL, NULL, NULL}
+};
 
-                                   [Image]
+/* calculate the number of menu_item's */
+static int nmenu_items = sizeof(menu_items) / sizeof(menu_items[0]);
 
-The solution is to place the preview and the label into a 2x1 table and by
-attaching them with the following paramters (this is one possible variations
-of course. The key is no GTK_FILL in the second attachment):
+static int initialize = TRUE;
+static GtkMenuFactory *factory = NULL;
+static GtkMenuFactory *subfactory[1];
+static GHashTable *entry_ht = NULL;
 
-gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
-                 0,
-                 GTK_EXPAND|GTK_FILL,
-                 0,0);
-gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
-                 GTK_EXPAND,
-                 GTK_EXPAND,
-                 0,0);
+void get_main_menu(GtkWidget ** menubar, GtkAcceleratorTable ** table)
+{
+    if (initialize)
+           menus_init();
+    
+    if (menubar)
+           *menubar = subfactory[0]->widget;
+    if (table)
+           *table = subfactory[0]->table;
+}
+
+void menus_init(void)
+{
+    if (initialize) {
+       initialize = FALSE;
+       
+       factory = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
+       subfactory[0] = gtk_menu_factory_new(GTK_MENU_FACTORY_MENU_BAR);
+       
+       gtk_menu_factory_add_subfactory(factory, subfactory[0], "<Main>");
+       menus_create(menu_items, nmenu_items);
+    }
+}
+
+void menus_create(GtkMenuEntry * entries, int nmenu_entries)
+{
+    char *accelerator;
+    int i;
+    
+    if (initialize)
+           menus_init();
+    
+    if (entry_ht)
+           for (i = 0; i < nmenu_entries; i++) {
+               accelerator = g_hash_table_lookup(entry_ht, entries[i].path);
+               if (accelerator) {
+                   if (accelerator[0] == '\0')
+                           entries[i].accelerator = NULL;
+                   else
+                           entries[i].accelerator = accelerator;
+               }
+           }
+    gtk_menu_factory_add_entries(factory, entries, nmenu_entries);
+    
+    for (i = 0; i < nmenu_entries; i++)
+           if (entries[i].widget) {
+               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "install_accelerator",
+                                  (GtkSignalFunc) menus_install_accel,
+                                  entries[i].path);
+               gtk_signal_connect(GTK_OBJECT(entries[i].widget), "remove_accelerator",
+                                  (GtkSignalFunc) menus_remove_accel,
+                                  entries[i].path);
+           }
+}
+
+static gint menus_install_accel(GtkWidget * widget, gchar * signal_name, gchar key, gchar modifiers, gchar * path)
+{
+    char accel[64];
+    char *t1, t2[2];
+    
+    accel[0] = '\0';
+    if (modifiers & GDK_CONTROL_MASK)
+           strcat(accel, "<control>");
+    if (modifiers & GDK_SHIFT_MASK)
+           strcat(accel, "<shift>");
+    if (modifiers & GDK_MOD1_MASK)
+           strcat(accel, "<alt>");
+    
+    t2[0] = key;
+    t2[1] = '\0';
+    strcat(accel, t2);
+    
+    if (entry_ht) {
+       t1 = g_hash_table_lookup(entry_ht, path);
+       g_free(t1);
+    } else
+           entry_ht = g_hash_table_new(g_str_hash, g_str_equal);
+    
+    g_hash_table_insert(entry_ht, path, g_strdup(accel));
+    
+    return TRUE;
+}
+
+static void menus_remove_accel(GtkWidget * widget, gchar * signal_name, gchar * path)
+{
+    char *t;
+    
+    if (entry_ht) {
+       t = g_hash_table_lookup(entry_ht, path);
+       g_free(t);
+       
+       g_hash_table_insert(entry_ht, path, g_strdup(""));
+    }
+}
+
+void menus_set_sensitive(char *path, int sensitive)
+{
+    GtkMenuPath *menu_path;
+    
+    if (initialize)
+           menus_init();
+    
+    menu_path = gtk_menu_factory_find(factory, path);
+    if (menu_path)
+           gtk_widget_set_sensitive(menu_path->widget, sensitive);
+    else
+           g_warning("Unable to set sensitivity for menu which doesn't exist: %s", path);
+}
+/* example-end */
+</verb></tscreen>
+
+And here's the mfmain.h
+
+<tscreen><verb>
+/* example-start menu mfmain.h */
+
+#ifndef __MFMAIN_H__
+#define __MFMAIN_H__
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+void file_quit_cmd_callback(GtkWidget *widget, gpointer data);
+
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+
+#endif /* __MFMAIN_H__ */
+/* example-end */
+</verb></tscreen>
+
+And mfmain.c
+
+<tscreen><verb>
+/* example-start menu mfmain.c */
+
+#include <gtk/gtk.h>
+
+#include "mfmain.h"
+#include "menufactory.h"
+
+
+int main(int argc, char *argv[])
+{
+    GtkWidget *window;
+    GtkWidget *main_vbox;
+    GtkWidget *menubar;
+    
+    GtkAcceleratorTable *accel;
+    
+    gtk_init(&amp;argc, &amp;argv);
+    
+    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_signal_connect(GTK_OBJECT(window), "destroy", 
+                      GTK_SIGNAL_FUNC(file_quit_cmd_callback), 
+                      "WM destroy");
+    gtk_window_set_title(GTK_WINDOW(window), "Menu Factory");
+    gtk_widget_set_usize(GTK_WIDGET(window), 300, 200);
+    
+    main_vbox = gtk_vbox_new(FALSE, 1);
+    gtk_container_border_width(GTK_CONTAINER(main_vbox), 1);
+    gtk_container_add(GTK_CONTAINER(window), main_vbox);
+    gtk_widget_show(main_vbox);
+    
+    get_main_menu(&amp;menubar, &amp;accel);
+    gtk_window_add_accelerator_table(GTK_WINDOW(window), accel);
+    gtk_box_pack_start(GTK_BOX(main_vbox), menubar, FALSE, TRUE, 0);
+    gtk_widget_show(menubar);
+    
+    gtk_widget_show(window);
+    gtk_main();
+    
+    return(0);
+}
+
+/* This is just to demonstrate how callbacks work when using the
+ * menufactory.  Often, people put all the callbacks from the menus
+ * in a separate file, and then have them call the appropriate functions
+ * from there.  Keeps it more organized. */
+void file_quit_cmd_callback (GtkWidget *widget, gpointer data)
+{
+    g_print ("%s\n", (char *) data);
+    gtk_exit(0);
+}
+/* example-end */
+</verb></tscreen>
+
+And a makefile so it'll be easier to compile it.
+
+<tscreen><verb>
+# Makefile.mf
+
+CC      = gcc
+PROF    = -g
+C_FLAGS =  -Wall $(PROF) -L/usr/local/include -DDEBUG
+L_FLAGS =  $(PROF) -L/usr/X11R6/lib -L/usr/local/lib 
+L_POSTFLAGS = -lgtk -lgdk -lglib -lXext -lX11 -lm
+PROGNAME = menufactory
+
+O_FILES = menufactory.o mfmain.o
+
+$(PROGNAME): $(O_FILES)
+       rm -f $(PROGNAME)
+       $(CC) $(L_FLAGS) -o $(PROGNAME) $(O_FILES) $(L_POSTFLAGS)
+
+.c.o: 
+       $(CC) -c $(C_FLAGS) $<
+
+clean: 
+       rm -f core *.o $(PROGNAME) nohup.out
+distclean: clean 
+       rm -f *~
+</verb></tscreen>
+
+For now, there's only this example.  An explanation and lots 'o' comments
+will follow later.
+
+<!-- ***************************************************************** -->
+<sect> Text Widget
+<!-- ***************************************************************** -->
+<p>
+The Text widget allows multiple lines of text to be displayed and edited.
+It supports both multi-colored and multi-font text, allowing them to be
+mixed in any way we wish. It also has a wide set of key based text editing
+commands, which are compatible with Emacs.
+
+The text widget supports full cut-and-paste facilities, including the use
+of double- and triple-click to select a word and a whole line, respectively.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Creating and Configuring a Text box
+<p>
+There is only one function for creating a new Text widget.
+<tscreen><verb>
+GtkWidget *gtk_text_new( GtkAdjustment *hadj,
+                         GtkAdjustment *vadj );
+</verb></tscreen>
+
+The arguments allow us to give the Text widget pointers to Adjustments
+that can be used to track the viewing position of the widget. Passing NULL
+values to either or both of these arguments will cause the gtk_text_new
+function to create it's own.
+
+<tscreen><verb>
+void gtk_text_set_adjustments( GtkText       *text,
+                               GtkAdjustment *hadj,
+                               GtkAdjustment *vadj );
+</verb></tscreen>
+
+The above function allows the horizontal and vertical adjustments of a
+Text widget to be changed at any time.
+
+The text widget will not automatically create it's own scrollbars when
+the amount of text to be displayed is too long for the display window. We
+therefore have to create and add them to the display layout ourselves.
+
+<tscreen><verb>
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT(text)->vadj);
+  gtk_box_pack_start(GTK_BOX(hbox), vscrollbar, FALSE, FALSE, 0);
+  gtk_widget_show (vscrollbar);
+</verb></tscreen>
+
+The above code snippet creates a new vertical scrollbar, and attaches
+it to the vertical adjustment of the text widget, <tt/text/. It then packs
+it into a box in the normal way.
+
+Note, currently the GtkText widget does not support horizontal scrollbars.
+
+There are two main ways in which a Text widget can be used: to allow the
+user to edit a body of text, or to allow us to display multiple lines of
+text to the user. In order for us to switch between these modes of
+operation, the text widget has the following function:
+
+<tscreen><verb>
+void gtk_text_set_editable( GtkText *text,
+                            gint     editable );
+</verb></tscreen>
+
+The <tt/editable/ argument is a TRUE or FALSE value that specifies whether
+the user is permitted to edit the contents of the Text widget. When the
+text widget is editable, it will display a cursor at the current insertion
+point.
+
+You are not, however, restricted to just using the text widget in these
+two modes. You can toggle the editable state of the text widget at any
+time, and can insert text at any time.
+
+The text widget wraps lines of text that are too long to
+fit onto a single line of the display window. It's default behaviour is
+to break words across line breaks. This can be changed using the next
+function:
+
+<tscreen><verb>
+void gtk_text_set_word_wrap( GtkText *text,
+                             gint     word_wrap );
+</verb></tscreen>
+
+Using this function allows us to specify that the text widget should
+wrap long lines on word boundaries. The <tt/word_wrap/ argument is a
+TRUE or FALSE value.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Text Manipulation
+<P>
+The current insertion point of a Text widget can be set using
+<tscreen><verb>
+void gtk_text_set_point( GtkText *text,
+                         guint    index );
+</verb></tscreen>
+
+where <tt/index/ is the position to set the insertion point.
+
+Analogous to this is the function for getting the current insertion point:
+
+<tscreen><verb>
+guint gtk_text_get_point( GtkText *text );
+</verb></tscreen>
+
+A function that is useful in combination with the above two functions is
+
+<tscreen><verb>
+guint gtk_text_get_length( GtkText *text );
+</verb></tscreen>
+
+which returns the current length of the Text widget. The length is the
+number of characters that are within the text block of the widget,
+including characters such as carriage-return, which marks the end of lines.
+
+In order to insert text at the current insertion point of a Text
+widget, the function gtk_text_insert is used, which also allows us to
+specify background and foreground colors and a font for the text.
+
+<tscreen><verb>
+void gtk_text_insert( GtkText    *text,
+                      GdkFont    *font,
+                      GdkColor   *fore,
+                      GdkColor   *back,
+                      const char *chars,
+                      gint        length );
+</verb></tscreen>
+
+Passing a value of <tt/NULL/ in as the value for the foreground color,
+background colour or font will result in the values set within the widget
+style to be used. Using a value of <tt/-1/ for the length parameter will
+result in the whole of the text string given being inserted.
+
+The text widget is one of the few within GTK that redraws itself
+dynamically, outside of the gtk_main function. This means that all changes
+to the contents of the text widget take effect immediately. This may be
+undesirable when performing multiple changes to the text widget. In order
+to allow us to perform multiple updates to the text widget without it
+continuously redrawing, we can freeze the widget, which temporarily stops
+it from automatically redrawing itself every time it is changed. We can
+then thaw the widget after our updates are complete.
+
+The following two functions perform this freeze and thaw action:
+
+<tscreen><verb>
+void gtk_text_freeze( GtkText *text );
+
+void gtk_text_thaw( GtkText *text );         
+</verb></tscreen>
+
+Text is deleted from the text widget relative to the current insertion
+point by the following two functions. The return value is a TRUE or
+FALSE indicator of whether the operation was successful.
+
+<tscreen><verb>
+gint gtk_text_backward_delete( GtkText *text,
+                               guint    nchars );
+
+gint gtk_text_forward_delete ( GtkText *text,
+                               guint    nchars );
+</verb></tscreen>
+
+If you want to retrieve the contents of the text widget, then the macro 
+<tt/GTK_TEXT_INDEX(t, index)/ allows you to retrieve the character at
+position <tt/index/ within the text widget <tt/t/.
+
+To retrieve larger blocks of text, we can use the function
+
+<tscreen><verb>
+gchar *gtk_editable_get_chars( GtkEditable *editable,
+                               gint         start_pos,
+                               gint         end_pos );   
+</verb></tscreen>
+
+This is a function of the parent class of the text widget. A value of -1 as
+<tt/end_pos/ signifies the end of the text. The index of the text starts at 0.
+
+The function allocates a new chunk of memory for the text block, so don't forget
+to free it with a call to g_free when you have finished with it.
+<!-- ----------------------------------------------------------------- -->
+<sect1>Keyboard Shortcuts
+<p>
+The text widget has a number of pre-installed keyboard shotcuts for common
+editing, motion and selection functions. These are accessed using Control
+and Alt key combinations.
+
+In addition to these, holding down the Control key whilst using cursor key
+movement will move the cursor by words rather than characters. Holding down
+Shift whilst using cursor movement will extend the selection.
+
+<sect2>Motion Shotcuts
+<p>
+<itemize>
+<item> Ctrl-A   Beginning of line
+<item> Ctrl-E   End of line
+<item> Ctrl-N   Next Line
+<item> Ctrl-P   Previous Line
+<item> Ctrl-B   Backward one character
+<item> Ctrl-F   Forward one character
+<item> Alt-B    Backward one word
+<item> Alt-F    Forward one word
+</itemize>
+
+<sect2>Editing Shortcuts
+<p>
+<itemize>
+<item> Ctrl-H   Delete Backward Character (Backspace)
+<item> Ctrl-D   Delete Forward Character (Delete)
+<item> Ctrl-W   Delete Backward Word
+<item> Alt-D    Delete Forward Word
+<item> Ctrl-K   Delete to end of line
+<item> Ctrl-U   Delete line
+</itemize>
+
+<sect2>Selection Shortcuts
+<p>
+<itemize>
+<item> Ctrl-X   Cut to clipboard
+<item> Ctrl-C   Copy to clipboard
+<item> Ctrl-V   Paste from clipboard
+</itemize>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>A GtkText Example
+<p>
+<tscreen><verb>
+/* example-start text text.c */
+
+/* text.c */
+
+#include <stdio.h>
+#include <gtk/gtk.h>
+
+void text_toggle_editable (GtkWidget *checkbutton,
+                          GtkWidget *text)
+{
+  gtk_text_set_editable(GTK_TEXT(text),
+                       GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void text_toggle_word_wrap (GtkWidget *checkbutton,
+                           GtkWidget *text)
+{
+  gtk_text_set_word_wrap(GTK_TEXT(text),
+                        GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void close_application( GtkWidget *widget, gpointer data )
+{
+       gtk_main_quit();
+}
+
+int main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *hbox;
+  GtkWidget *button;
+  GtkWidget *check;
+  GtkWidget *separator;
+  GtkWidget *table;
+  GtkWidget *vscrollbar;
+  GtkWidget *text;
+  GdkColormap *cmap;
+  GdkColor colour;
+  GdkFont *fixed_font;
+
+  FILE *infile;
+
+  gtk_init (&amp;argc, &amp;argv);
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_usize (window, 600, 500);
+  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
+  gtk_container_border_width (GTK_CONTAINER (window), 0);
+  
+  
+  box1 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), box1);
+  gtk_widget_show (box1);
+  
+  
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
+  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+  gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
+  gtk_widget_show (table);
+  
+  /* Create the GtkText widget */
+  text = gtk_text_new (NULL, NULL);
+  gtk_text_set_editable (GTK_TEXT (text), TRUE);
+  gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (text);
+
+  /* Add a vertical scrollbar to the GtkText widget */
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+  gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+                   GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (vscrollbar);
+
+  /* Get the system colour map and allocate the colour red */
+  cmap = gdk_colormap_get_system();
+  colour.red = 0xffff;
+  colour.green = 0;
+  colour.blue = 0;
+  if (!gdk_color_alloc(cmap, &amp;colour)) {
+    g_error("couldn't allocate colour");
+  }
+
+  /* Load a fixed font */
+  fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
+
+  /* Realizing a widget creates a window for it, ready for us to insert some text */
+  gtk_widget_realize (text);
+
+  /* Freeze the text widget, ready for multiple updates */
+  gtk_text_freeze (GTK_TEXT (text));
+  
+  /* Insert some coloured text */
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+                  "Supports ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;colour, NULL,
+                  "colored ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &amp;text->style->black, NULL,
+                  "text and different ", -1);
+  gtk_text_insert (GTK_TEXT (text), fixed_font, &amp;text->style->black, NULL,
+                  "fonts\n\n", -1);
+  
+  /* Load the file text.c into the text window */
+
+  infile = fopen("text.c", "r");
+  
+  if (infile) {
+    char buffer[1024];
+    int nchars;
+    
+    while (1)
+      {
+       nchars = fread(buffer, 1, 1024, infile);
+       gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
+                        NULL, buffer, nchars);
+       
+       if (nchars < 1024)
+         break;
+      }
+    
+    fclose (infile);
+  }
+
+  /* Thaw the text widget, allowing the updates to become visible */  
+  gtk_text_thaw (GTK_TEXT (text));
+  
+  hbox = gtk_hbutton_box_new ();
+  gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  check = gtk_check_button_new_with_label("Editable");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_editable), text);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
+  gtk_widget_show (check);
+  check = gtk_check_button_new_with_label("Wrap Words");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
+  gtk_widget_show (check);
+
+  separator = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+  gtk_widget_show (separator);
+
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  button = gtk_button_new_with_label ("close");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+  gtk_widget_grab_default (button);
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+  
+  return 0;       
+}
+/* example-end */
+</verb></tscreen>
+
+
+<!-- ***************************************************************** -->
+<sect> Undocumented Widgets
+<!-- ***************************************************************** -->
+<p>
+These all require authors! :)  Please consider contributing to our tutorial.
+
+If you must use one of these widgets that are undocumented, I strongly
+suggest you take a look at their respective header files in the GTK
+distribution. GTK's function names are very descriptive.  Once you have an
+understanding of how things work, it's not difficult to figure out how to
+use a widget simply by looking at it's function declarations.  This, along
+with a few examples from others' code, and it should be no problem.
+
+When you do come to understand all the functions of a new undocumented
+widget, please consider writing a tutorial on it so others may benifit
+from your time.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Adjustments
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Toolbar
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Fixed Container
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Range Controls
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Curves
+<p>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Previews
+<p>
+
+(This may need to be rewritten to follow the style of the rest of the tutorial)
+
+<tscreen><verb>
+
+Previews serve a number of purposes in GIMP/GTK. The most important one is
+this. High quality images may take up to tens of megabytes of memory - easy!
+Any operation on an image that big is bound to take a long time. If it takes
+you 5-10 trial-and-errors (i.e. 10-20 steps, since you have to revert after
+you make an error) to choose the desired modification, it make take you
+literally hours to make the right one - if you don't run out of memory
+first. People who have spent hours in color darkrooms know the feeling.
+Previews to the rescue!
+
+But the annoyance of the delay is not the only issue. Oftentimes it is
+helpful to compare the Before and After versions side-by-side or at least
+back-to-back. If you're working with big images and 10 second delays,
+obtaining the Before and After impressions is, to say the least, difficult.
+For 30M images (4"x6", 600dpi, 24 bit) the side-by-side comparison is right
+out for most people, while back-to-back is more like back-to-1001, 1002,
+..., 1010-back! Previews to the rescue!
+
+But there's more. Previews allow for side-by-side pre-previews. In other
+words, you write a plug-in (e.g. the filterpack simulation) which would have
+a number of here's-what-it-would-look-like-if-you-were-to-do-this previews.
+An approach like this acts as a sort of a preview palette and is very
+effective fow subtle changes. Let's go previews!
+
+There's more. For certain plug-ins real-time image-specific human
+intervention maybe necessary. In the SuperNova plug-in, for example, the
+user is asked to enter the coordinates of the center of the future
+supernova. The easiest way to do this, really, is to present the user with a
+preview and ask him to intereactively select the spot. Let's go previews!
+
+Finally, a couple of misc uses. One can use previews even when not working
+with big images. For example, they are useful when rendering compicated
+patterns. (Just check out the venerable Diffraction plug-in + many other
+ones!) As another example, take a look at the colormap rotation plug-in
+(work in progress). You can also use previews for little logo's inside you
+plug-ins and even for an image of yourself, The Author. Let's go previews!
+
+When Not to Use Previews
+
+Don't use previews for graphs, drawing etc. GDK is much faster for that. Use
+previews only for rendered images!
+
+Let's go previews!
+
+You can stick a preview into just about anything. In a vbox, an hbox, a
+table, a button, etc. But they look their best in tight frames around them.
+Previews by themselves do not have borders and look flat without them. (Of
+course, if the flat look is what you want...) Tight frames provide the
+necessary borders.
+
+                               [Image][Image]
+
+Previews in many ways are like any other widgets in GTK (whatever that
+means) except they possess an addtional feature: they need to be filled with
+some sort of an image! First, we will deal exclusively with the GTK aspect
+of previews and then we'll discuss how to fill them.
+
+GtkWidget *preview!
+
+Without any ado:
+
+                              /* Create a preview widget,
+                              set its size, an show it */
+GtkWidget *preview;
+preview=gtk_preview_new(GTK_PREVIEW_COLOR)
+                              /*Other option:
+                              GTK_PREVIEW_GRAYSCALE);*/
+gtk_preview_size (GTK_PREVIEW (preview), WIDTH, HEIGHT);
+gtk_widget_show(preview);
+my_preview_rendering_function(preview);
+
+Oh yeah, like I said, previews look good inside frames, so how about:
+
+GtkWidget *create_a_preview(int        Width,
+                            int        Height,
+                            int        Colorfulness)
+{
+  GtkWidget *preview;
+  GtkWidget *frame;
+  
+  frame = gtk_frame_new(NULL);
+  gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+  gtk_container_border_width (GTK_CONTAINER(frame),0);
+  gtk_widget_show(frame);
+
+  preview=gtk_preview_new (Colorfulness?GTK_PREVIEW_COLOR
+                                       :GTK_PREVIEW_GRAYSCALE);
+  gtk_preview_size (GTK_PREVIEW (preview), Width, Height);
+  gtk_container_add(GTK_CONTAINER(frame),preview);
+  gtk_widget_show(preview);
+
+  my_preview_rendering_function(preview);
+  return frame;
+}
+
+That's my basic preview. This routine returns the "parent" frame so you can
+place it somewhere else in your interface. Of course, you can pass the
+parent frame to this routine as a parameter. In many situations, however,
+the contents of the preview are changed continually by your application. In
+this case you may want to pass a pointer to the preview to a
+"create_a_preview()" and thus have control of it later.
+
+One more important note that may one day save you a lot of time. Sometimes
+it is desirable to label you preview. For example, you may label the preview
+containing the original image as "Original" and the one containing the
+modified image as "Less Original". It might occure to you to pack the
+preview along with the appropriate label into a vbox. The unexpected caveat
+is that if the label is wider than the preview (which may happen for a
+variety of reasons unforseeable to you, from the dynamic decision on the
+size of the preview to the size of the font) the frame expands and no longer
+fits tightly over the preview. The same problem can probably arise in other
+situations as well.
+
+                                   [Image]
+
+The solution is to place the preview and the label into a 2x1 table and by
+attaching them with the following paramters (this is one possible variations
+of course. The key is no GTK_FILL in the second attachment):
+
+gtk_table_attach(GTK_TABLE(table),label,0,1,0,1,
+                 0,
+                 GTK_EXPAND|GTK_FILL,
+                 0,0);
+gtk_table_attach(GTK_TABLE(table),frame,0,1,1,2,
+                 GTK_EXPAND,
+                 GTK_EXPAND,
+                 0,0);
 
 
 And here's the result:
 
-                                   [Image]
+                                   [Image]
+
+Misc
+
+Making a preview clickable is achieved most easily by placing it in a
+button. It also adds a nice border around the preview and you may not even
+need to place it in a frame. See the Filter Pack Simulation plug-in for an
+example.
+
+This is pretty much it as far as GTK is concerned.
+
+Filling In a Preview
+
+In order to familiarize ourselves with the basics of filling in previews,
+let's create the following pattern (contrived by trial and error):
+
+                                   [Image]
+
+void
+my_preview_rendering_function(GtkWidget     *preview)
+{
+#define SIZE 100
+#define HALF (SIZE/2)
+
+  guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
+  gint i, j;                             /* Coordinates    */
+  double r, alpha, x, y;
+
+  if (preview==NULL) return; /* I usually add this when I want */
+                             /* to avoid silly crashes. You    */
+                             /* should probably make sure that */
+                             /* everything has been nicely     */
+                             /* initialized!                   */
+  for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape?  */
+                                         /* glib.h contains ABS(x).   */
+        row[i*3+0] = sqrt(1-r)*255;      /* Define Red                */
+        row[i*3+1] = 128;                /* Define Green              */
+        row[i*3+2] = 224;                /* Define Blue               */
+      }                                  /* "+0" is for alignment!    */
+      else {
+        row[i*3+0] = r*255;
+        row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
+        row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
+      }
+    }
+    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
+    /* Insert "row" into "preview" starting at the point with  */
+    /* coordinates (0,j) first column, j_th row extending SIZE */
+    /* pixels to the right */
+  }
+
+  free(row); /* save some space */
+  gtk_widget_draw(preview,NULL); /* what does this do? */
+  gdk_flush(); /* or this? */
+}
+
+Non-GIMP users can have probably seen enough to do a lot of things already.
+For the GIMP users I have a few pointers to add.
+
+Image Preview
+
+It is probably wize to keep a reduced version of the image around with just
+enough pixels to fill the preview. This is done by selecting every n'th
+pixel where n is the ratio of the size of the image to the size of the
+preview. All further operations (including filling in the previews) are then
+performed on the reduced number of pixels only. The following is my
+implementation of reducing the image. (Keep in mind that I've had only basic
+C!)
+
+(UNTESTED CODE ALERT!!!)
+
+typedef struct {
+  gint      width;
+  gint      height;
+  gint      bbp;
+  guchar    *rgb;
+  guchar    *mask;
+} ReducedImage;
+
+enum {
+  SELECTION_ONLY,
+  SELCTION_IN_CONTEXT,
+  ENTIRE_IMAGE
+};
+
+ReducedImage *Reduce_The_Image(GDrawable *drawable,
+                               GDrawable *mask,
+                               gint LongerSize,
+                               gint Selection)
+{
+  /* This function reduced the image down to the the selected preview size */
+  /* The preview size is determine by LongerSize, i.e. the greater of the  */
+  /* two dimentions. Works for RGB images only!                            */
+  gint RH, RW;          /* Reduced height and reduced width                */
+  gint width, height;   /* Width and Height of the area being reduced      */
+  gint bytes=drawable->bpp;
+  ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
+
+  guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
+  gint i, j, whichcol, whichrow, x1, x2, y1, y2;
+  GPixelRgn srcPR, srcMask;
+  gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire  */
+                             /* image.                                     */
+
+  gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
+  width  = x2-x1;
+  height = y2-y1;
+  /* If there's a SELECTION, we got its bounds!)
+
+  if (width != drawable->width &amp;&amp; height != drawable->height)
+    NoSelectionMade=FALSE;
+  /* Become aware of whether the user has made an active selection   */
+  /* This will become important later, when creating a reduced mask. */
+
+  /* If we want to preview the entire image, overrule the above!  */
+  /* Of course, if no selection has been made, this does nothing! */
+  if (Selection==ENTIRE_IMAGE) {
+    x1=0;
+    x2=drawable->width;
+    y1=0;
+    y2=drawable->height;
+  }
+
+  /* If we want to preview a selection with some surronding area we */
+  /* have to expand it a little bit. Consider it a bit of a riddle. */
+  if (Selection==SELECTION_IN_CONTEXT) {
+    x1=MAX(0,                x1-width/2.0);
+    x2=MIN(drawable->width,  x2+width/2.0);
+    y1=MAX(0,                y1-height/2.0);
+    y2=MIN(drawable->height, y2+height/2.0);
+  }
+
+  /* How we can determine the width and the height of the area being */
+  /* reduced.                                                        */
+  width  = x2-x1;
+  height = y2-y1;
+
+  /* The lines below determine which dimension is to be the longer   */
+  /* side. The idea borrowed from the supernova plug-in. I suspect I */
+  /* could've thought of it myself, but the truth must be told.      */
+  /* Plagiarism stinks!                                               */
+  if (width>height) {
+    RW=LongerSize;
+    RH=(float) height * (float) LongerSize/ (float) width;
+  }
+  else {
+    RH=LongerSize;
+    RW=(float)width * (float) LongerSize/ (float) height;
+  }
+
+  /* The intire image is stretched into a string! */
+  tempRGB   = (guchar *) malloc(RW*RH*bytes);
+  tempmask  = (guchar *) malloc(RW*RH);
+
+  gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
+  gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height, FALSE, FALSE);
+
+  /* Grab enough to save a row of image and a row of mask. */
+  src_row       = (guchar *) malloc (width*bytes);
+  src_mask_row  = (guchar *) malloc (width);
+
+  for (i=0; i < RH; i++) {
+    whichrow=(float)i*(float)height/(float)RH;
+    gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
+    gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
+
+    for (j=0; j < RW; j++) {
+      whichcol=(float)j*(float)width/(float)RW;
+
+      /* No selection made = each point is completely selected! */
+      if (NoSelectionMade)
+        tempmask[i*RW+j]=255;
+      else
+        tempmask[i*RW+j]=src_mask_row[whichcol];
+
+      /* Add the row to the one long string which now contains the image! */
+      tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
+      tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
+      tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
+
+      /* Hold on to the alpha as well */
+      if (bytes==4)
+        tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
+    }
+  }
+  temp->bpp=bytes;
+  temp->width=RW;
+  temp->height=RH;
+  temp->rgb=tempRGB;
+  temp->mask=tempmask;
+  return temp;
+}
+
+The following is a preview function which used the same ReducedImage type!
+Note that it uses fakes transparancy (if one is present by means of
+fake_transparancy which is defined as follows:
+
+gint fake_transparency(gint i, gint j)
+{
+  if ( ((i%20)- 10) * ((j%20)- 10)>0   )
+    return 64;
+  else
+    return 196;
+}
+
+Now here's the preview function:
+
+void
+my_preview_render_function(GtkWidget     *preview,
+                           gint          changewhat,
+                           gint          changewhich)
+{
+  gint Inten, bytes=drawable->bpp;
+  gint i, j, k;
+  float partial;
+  gint RW=reduced->width;
+  gint RH=reduced->height;
+  guchar *row=malloc(bytes*RW);;
+
+
+  for (i=0; i < RH; i++) {
+    for (j=0; j < RW; j++) {
+
+      row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
+      row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
+      row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
+
+      if (bytes==4)
+        for (k=0; k<3; k++) {
+          float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
+          row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
+        }
+    }
+    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
+  }
+
+  free(a);
+  gtk_widget_draw(preview,NULL);
+  gdk_flush();
+}
+
+Applicable Routines
+
+guint           gtk_preview_get_type           (void);
+/* No idea */
+void            gtk_preview_uninit             (void);
+/* No idea */
+GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
+/* Described above */
+void            gtk_preview_size               (GtkPreview      *preview,
+                                                gint             width,
+                                                gint             height);
+/* Allows you to resize an existing preview.    */
+/* Apparantly there's a bug in GTK which makes  */
+/* this process messy. A way to clean up a mess */
+/* is to manually resize the window containing  */
+/* the preview after resizing the preview.      */
+
+void            gtk_preview_put                (GtkPreview      *preview,
+                                                GdkWindow       *window,
+                                                GdkGC           *gc,
+                                                gint             srcx,
+                                                gint             srcy,
+                                                gint             destx,
+                                                gint             desty,
+                                                gint             width,
+                                                gint             height);
+/* No idea */
+
+void            gtk_preview_put_row            (GtkPreview      *preview,
+                                                guchar          *src,
+                                                guchar          *dest,
+                                                gint             x,
+                                                gint             y,
+                                                gint             w);
+/* No idea */
+
+void            gtk_preview_draw_row           (GtkPreview      *preview,
+                                                guchar          *data,
+                                                gint             x,
+                                                gint             y,
+                                                gint             w);
+/* Described in the text */
+
+void            gtk_preview_set_expand         (GtkPreview      *preview,
+                                                gint             expand);
+/* No idea */
+
+/* No clue for any of the below but    */
+/* should be standard for most widgets */
+void            gtk_preview_set_gamma          (double           gamma);
+void            gtk_preview_set_color_cube     (guint            nred_shades,
+                                                guint            ngreen_shades,
+                                                guint            nblue_shades,
+                                                guint            ngray_shades);
+void            gtk_preview_set_install_cmap   (gint             install_cmap);
+void            gtk_preview_set_reserved       (gint             nreserved);
+GdkVisual*      gtk_preview_get_visual         (void);
+GdkColormap*    gtk_preview_get_cmap           (void);
+GtkPreviewInfo* gtk_preview_get_info           (void);
+
+That's all, folks!
+
+</verb></tscreen>
+
+<!-- ***************************************************************** -->
+<sect>The EventBox Widget<label id="sec_The_EventBox_Widget">
+<!-- ***************************************************************** -->
+<p> 
+Some gtk widgets don't have associated X windows, so they just draw on 
+their parents. Because of this, they cannot recieve events
+and if they are incorrectly sized, they don't clip so you can get
+messy overwritting etc. If you require more from these widgets, the
+EventBox is for you.
+
+At first glance, the EventBox widget might appear to be totally
+useless. It draws nothing on the screen and responds to no
+events. However, it does serve a function - it provides an X window for
+its child widget. This is important as many GTK widgets do not
+have an associated X window. Not having an X window saves memory and
+improves performance, but also has some drawbacks. A widget without an
+X window cannot receive events, and does not perform any clipping on
+it's contents. Although the name <em/EventBox/ emphasizes the
+event-handling function, the widget can also be used for clipping. 
+(And more ... see the example below.)
+
+To create a new EventBox widget, use:
+
+<tscreen><verb>
+GtkWidget *gtk_event_box_new( void );
+</verb></tscreen>
+
+A child widget can then be added to this EventBox:
+
+<tscreen><verb>
+gtk_container_add( GTK_CONTAINER(event_box), widget );
+</verb></tscreen>
+
+The following example demonstrates both uses of an EventBox - a label
+is created that is clipped to a small box, and set up so that a
+mouse-click on the label causes the program to exit.
+
+<tscreen><verb>
+/* example-start eventbox eventbox.c */
+
+#include <gtk/gtk.h>
+
+int 
+main (int argc, char *argv[])
+{
+    GtkWidget *window;
+    GtkWidget *event_box;
+    GtkWidget *label;
+    
+    gtk_init (&amp;argc, &amp;argv);
+    
+    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+    
+    gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+    
+    gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+    
+    gtk_container_border_width (GTK_CONTAINER (window), 10);
+    
+    /* Create an EventBox and add it to our toplevel window */
+    
+    event_box = gtk_event_box_new ();
+    gtk_container_add (GTK_CONTAINER(window), event_box);
+    gtk_widget_show (event_box);
+    
+    /* Create a long label */
+    
+    label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
+    gtk_container_add (GTK_CONTAINER (event_box), label);
+    gtk_widget_show (label);
+    
+    /* Clip it short. */
+    gtk_widget_set_usize (label, 110, 20);
+    
+    /* And bind an action to it */
+    gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
+    gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
+                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
+    
+    /* Yet one more thing you need an X window for ... */
+    
+    gtk_widget_realize (event_box);
+    gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
+    
+    gtk_widget_show (window);
+    
+    gtk_main ();
+    
+    return 0;
+}
+/* example-end */
+</verb></tscreen>
+
+<!-- ***************************************************************** -->
+<sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
+<!-- ***************************************************************** -->
+<p>
+This describes the functions used to operate on widgets.  These can be used
+to set style, padding, size etc.
+
+(Maybe I should make a whole section on accelerators.)
+
+<tscreen><verb>
+void gtk_widget_install_accelerator( GtkWidget           *widget,
+                                     GtkAcceleratorTable *table,
+                                     gchar               *signal_name,
+                                     gchar                key,
+                                     guint8               modifiers );
+
+void gtk_widget_remove_accelerator ( GtkWidget           *widget,
+                                     GtkAcceleratorTable *table,
+                                     gchar               *signal_name);
+
+void gtk_widget_activate( GtkWidget *widget );
+
+void gtk_widget_set_name( GtkWidget *widget,
+                          gchar     *name );
+
+gchar *gtk_widget_get_name( GtkWidget *widget );
+
+void gtk_widget_set_sensitive( GtkWidget *widget,
+                               gint       sensitive );
+
+void gtk_widget_set_style( GtkWidget *widget,
+                           GtkStyle  *style );
+                                          
+GtkStyle *gtk_widget_get_style( GtkWidget *widget );
+
+GtkStyle *gtk_widget_get_default_style( void );
+
+void gtk_widget_set_uposition( GtkWidget *widget,
+                               gint       x,
+                               gint       y );
+
+void gtk_widget_set_usize( GtkWidget *widget,
+                           gint       width,
+                           gint       height );
+
+void gtk_widget_grab_focus( GtkWidget *widget );
+
+void gtk_widget_show( GtkWidget *widget );
+
+void gtk_widget_hide( GtkWidget *widget );
+</verb></tscreen>
+
+<!-- ***************************************************************** -->
+<sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
+<!-- ***************************************************************** -->
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Timeouts
+<p>
+You may be wondering how you make GTK do useful work when in gtk_main.
+Well, you have several options. Using the following functions you can
+create a timeout function that will be called every "interval"
+milliseconds.
+
+<tscreen><verb>
+gint gtk_timeout_add( guint32     interval,
+                      GtkFunction function,
+                      gpointer    data );
+</verb></tscreen>
+
+The first argument is the number of milliseconds between calls to your
+function.  The second argument is the function you wish to have called, and
+the third, the data passed to this callback function. The return value is
+an integer "tag" which may be used to stop the timeout by calling:
+
+<tscreen><verb>
+void gtk_timeout_remove( gint tag );
+</verb></tscreen>
+
+You may also stop the timeout function by returning zero or FALSE from
+your callback function. Obviously this means if you want your function to
+continue to be called, it should return a non-zero value, ie TRUE.
+
+The declaration of your callback should look something like this:
+
+<tscreen><verb>
+gint timeout_callback( gpointer data );
+</verb></tscreen>
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Monitoring IO
+<p>
+Another nifty feature of GTK, is the ability to have it check for data on a
+file descriptor for you (as returned by open(2) or socket(2)). This is
+especially useful for networking applications. The function:
+
+<tscreen><verb>
+gint gdk_input_add( gint              source,
+                    GdkInputCondition condition,
+                    GdkInputFunction  function,
+                    gpointer          data );
+</verb></tscreen>
+
+Where the first argument is the file descriptor you wish to have watched,
+and the second specifies what you want GDK to look for.  This may be one of:
+
+<itemize>
+<item>GDK_INPUT_READ - Call your function when there is data ready for
+reading on your file descriptor.
+
+<item>GDK_INPUT_WRITE - Call your function when the file descriptor is
+ready for writing.
+</itemize>
+
+As I'm sure you've figured out already, the third argument is the function
+you wish to have called when the above conditions are satisfied, and the
+fourth is the data to pass to this function.
+
+The return value is a tag that may be used to stop GDK from monitoring this
+file descriptor using the following function.
+
+<tscreen><verb>
+void gdk_input_remove( gint tag );
+</verb></tscreen>
+
+The callback function should be declared as:
+
+<tscreen><verb>
+void input_callback( gpointer          data,
+                     gint              source, 
+                     GdkInputCondition condition );
+</verb></tscreen>
+
+Where <tt/source/ and <tt/condition/ are as specified above.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Idle Functions
+<p>
+<!-- Need to check on idle priorities - TRG -->
+What if you have a function you want called when nothing else is
+happening ?
+
+<tscreen><verb>
+gint gtk_idle_add( GtkFunction function,
+                   gpointer    data );
+</verb></tscreen>
+
+This causes GTK to call the specified function whenever nothing else is
+happening.
+
+<tscreen><verb>
+void gtk_idle_remove( gint tag );
+</verb></tscreen>
+
+I won't explain the meaning of the arguments as they follow very much like
+the ones above. The function pointed to by the first argument to
+gtk_idle_add will be called whenever the opportunity arises. As with the
+others, returning FALSE will stop the idle function from being called.
+
+<!-- ***************************************************************** -->
+<sect>Managing Selections
+<!-- ***************************************************************** -->
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Overview
+<p>
+One type of interprocess communication supported by GTK is
+<em>selections</em>. A selection identifies a chunk of data, for
+instance, a portion of text, selected by the user in some fashion, for
+instance, by dragging with the mouse. Only one application on a
+display, (the <em>owner</em> can own a particular selection at one
+time, so when a selection is claimed by one application, the previous
+owner must indicate to the user that selection has been
+relinquished. Other applications can request the contents of a
+selection in different forms, called <em>targets</em>. There can be
+any number of selections, but most X applications only handle one, the
+<em>primary selection</em>.
+
+In most cases, it isn't necessary for a GTK application to deal with
+selections itself. The standard widgets, such as the Entry widget,
+already have the capability to claim the selection when appropriate
+(e.g., when the user drags over text), and to retrieve the contents of
+the selection owned by another widget, or another application (e.g.,
+when the user clicks the second mouse button). However, there may be
+cases in which you want to give other widgets the ability to supply
+the selection, or you wish to retrieve targets not supported by
+default.
 
-Misc
+A fundamental concept needed to understand selection handling is that
+of the <em>atom</em>. An atom is an integer that uniquely identifies a
+string (on a certain display). Certain atoms are predefined by the X
+server, and in some cases there are constants in <tt>gtk.h</tt>
+corresponding to these atoms. For instance the constant
+<tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
+In other cases, you should use the functions
+<tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
+and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
+selections and targets are identifed by atoms.
 
-Making a preview clickable is achieved most easily by placing it in a
-button. It also adds a nice border around the preview and you may not even
-need to place it in a frame. See the Filter Pack Simulation plug-in for an
-example.
+<!-- ----------------------------------------------------------------- -->
+<sect1> Retrieving the selection
+<p>
+Retrieving the selection is an asynchronous process. To start the
+process, you call:
 
-This is pretty much it as far as GTK is concerned.
+<tscreen><verb>
+gint gtk_selection_convert( GtkWidget *widget, 
+                            GdkAtom    selection, 
+                            GdkAtom    target,
+                            guint32    time );
+</verb</tscreen>
 
-Filling In a Preview
+This <em>converts</em> the selection into the form specified by
+<tt/target/. If at all possible, the time field should be the time
+from the event that triggered the selection. This helps make sure that
+events occur in the order that the user requested them. However, if it
+is not available (for instance, if the conversion was triggered by
+a "clicked" signal), then you can use the constant
+<tt>GDK_CURRENT_TIME</tt>.
 
-In order to familiarize ourselves with the basics of filling in previews,
-let's create the following pattern (contrived by trial and error):
+When the selection owner responds to the request, a
+"selection_received" signal is sent to your application. The handler
+for this signal receives a pointer to a <tt>GtkSelectionData</tt>
+structure, which is defined as:
 
-                                   [Image]
+<tscreen><verb>
+struct _GtkSelectionData
+{
+  GdkAtom selection;
+  GdkAtom target;
+  GdkAtom type;
+  gint    format;
+  guchar *data;
+  gint    length;
+};
+</verb></tscreen>
+
+<tt>selection</tt> and <tt>target</tt> are the values you gave in your
+<tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
+identifies the type of data returned by the selection owner. Some
+possible values are "STRING", a string of latin-1 characters, "ATOM",
+a series of atoms, "INTEGER", an integer, etc. Most targets can only
+return one type. <tt/format/ gives the length of the units (for
+instance characters) in bits. Usually, you don't care about this when
+receiving data. <tt>data</tt> is a pointer to the returned data, and
+<tt>length</tt> gives the length of the returned data, in bytes. If
+<tt>length</tt> is negative, then an error occurred and the selection
+could not be retrieved. This might happen if no application owned the
+selection, or if you requested a target that the application didn't
+support. The buffer is actually guaranteed to be one byte longer than
+<tt>length</tt>; the extra byte will always be zero, so it isn't
+necessary to make a copy of strings just to null terminate them.
+
+In the following example, we retrieve the special target "TARGETS",
+which is a list of all targets into which the selection can be
+converted.
+
+<tscreen><verb>
+/* example-start selection gettargets.c */
+
+#include <gtk/gtk.h>
 
+void selection_received (GtkWidget *widget, 
+                        GtkSelectionData *selection_data, 
+                        gpointer data);
+
+/* Signal handler invoked when user clicks on the "Get Targets" button */
 void
-my_preview_rendering_function(GtkWidget     *preview)
+get_targets (GtkWidget *widget, gpointer data)
 {
-#define SIZE 100
-#define HALF (SIZE/2)
+  static GdkAtom targets_atom = GDK_NONE;
 
-  guchar *row=(guchar *) malloc(3*SIZE); /* 3 bits per dot */
-  gint i, j;                             /* Coordinates    */
-  double r, alpha, x, y;
+  /* Get the atom corresonding to the string "TARGETS" */
+  if (targets_atom == GDK_NONE)
+    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
 
-  if (preview==NULL) return; /* I usually add this when I want */
-                             /* to avoid silly crashes. You    */
-                             /* should probably make sure that */
-                             /* everything has been nicely     */
-                             /* initialized!                   */
-  for (j=0; j < ABS(cos(2*alpha)) ) { /* Are we inside the shape?  */
-                                         /* glib.h contains ABS(x).   */
-        row[i*3+0] = sqrt(1-r)*255;      /* Define Red                */
-        row[i*3+1] = 128;                /* Define Green              */
-        row[i*3+2] = 224;                /* Define Blue               */
-      }                                  /* "+0" is for alignment!    */
-      else {
-        row[i*3+0] = r*255;
-        row[i*3+1] = ABS(sin((float)i/SIZE*2*PI))*255;
-        row[i*3+2] = ABS(sin((float)j/SIZE*2*PI))*255;
-      }
+  /* And request the "TARGETS" target for the primary selection */
+  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
+                        GDK_CURRENT_TIME);
+}
+
+/* Signal handler called when the selections owner returns the data */
+void
+selection_received (GtkWidget *widget, GtkSelectionData *selection_data, 
+                   gpointer data)
+{
+  GdkAtom *atoms;
+  GList *item_list;
+  int i;
+
+  /* **** IMPORTANT **** Check to see if retrieval succeeded  */
+  if (selection_data->length < 0)
+    {
+      g_print ("Selection retrieval failed\n");
+      return;
     }
-    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,j,SIZE);
-    /* Insert "row" into "preview" starting at the point with  */
-    /* coordinates (0,j) first column, j_th row extending SIZE */
-    /* pixels to the right */
-  }
+  /* Make sure we got the data in the expected form */
+  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
+    {
+      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
+      return;
+    }
+  
+  /* Print out the atoms we received */
+  atoms = (GdkAtom *)selection_data->data;
 
-  free(row); /* save some space */
-  gtk_widget_draw(preview,NULL); /* what does this do? */
-  gdk_flush(); /* or this? */
+  item_list = NULL;
+  for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
+    {
+      char *name;
+      name = gdk_atom_name (atoms[i]);
+      if (name != NULL)
+       g_print ("%s\n",name);
+      else
+       g_print ("(bad atom)\n");
+    }
+
+  return;
 }
 
-Non-GIMP users can have probably seen enough to do a lot of things already.
-For the GIMP users I have a few pointers to add.
+int 
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *button;
+  
+  gtk_init (&amp;argc, &amp;argv);
 
-Image Preview
+  /* Create the toplevel window */
 
-It is probably wize to keep a reduced version of the image around with just
-enough pixels to fill the preview. This is done by selecting every n'th
-pixel where n is the ratio of the size of the image to the size of the
-preview. All further operations (including filling in the previews) are then
-performed on the reduced number of pixels only. The following is my
-implementation of reducing the image. (Keep in mind that I've had only basic
-C!)
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
 
-(UNTESTED CODE ALERT!!!)
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
 
-typedef struct {
-  gint      width;
-  gint      height;
-  gint      bbp;
-  guchar    *rgb;
-  guchar    *mask;
-} ReducedImage;
+  /* Create a button the user can click to get targets */
 
-enum {
-  SELECTION_ONLY,
-  SELCTION_IN_CONTEXT,
-  ENTIRE_IMAGE
-};
+  button = gtk_button_new_with_label ("Get Targets");
+  gtk_container_add (GTK_CONTAINER (window), button);
 
-ReducedImage *Reduce_The_Image(GDrawable *drawable,
-                               GDrawable *mask,
-                               gint LongerSize,
-                               gint Selection)
-{
-  /* This function reduced the image down to the the selected preview size */
-  /* The preview size is determine by LongerSize, i.e. the greater of the  */
-  /* two dimentions. Works for RGB images only!                            */
-  gint RH, RW;          /* Reduced height and reduced width                */
-  gint width, height;   /* Width and Height of the area being reduced      */
-  gint bytes=drawable->bpp;
-  ReducedImage *temp=(ReducedImage *)malloc(sizeof(ReducedImage));
+  gtk_signal_connect (GTK_OBJECT(button), "clicked",
+                     GTK_SIGNAL_FUNC (get_targets), NULL);
+  gtk_signal_connect (GTK_OBJECT(button), "selection_received",
+                     GTK_SIGNAL_FUNC (selection_received), NULL);
 
-  guchar *tempRGB, *src_row, *tempmask, *src_mask_row,R,G,B;
-  gint i, j, whichcol, whichrow, x1, x2, y1, y2;
-  GPixelRgn srcPR, srcMask;
-  gint NoSelectionMade=TRUE; /* Assume that we're dealing with the entire  */
-                             /* image.                                     */
+  gtk_widget_show (button);
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+/* example-end */
+</verb></tscreen>
 
-  gimp_drawable_mask_bounds (drawable->id, &amp;x1, &amp;y1, &amp;x2, &amp;y2);
-  width  = x2-x1;
-  height = y2-y1;
-  /* If there's a SELECTION, we got its bounds!)
+<!-- ----------------------------------------------------------------- -->
+<sect1> Supplying the selection 
+<p>
+Supplying the selection is a bit more complicated. You must register 
+handlers that will be called when your selection is requested. For
+each selection/target pair you will handle, you make a call to:
 
-  if (width != drawable->width &amp;&amp; height != drawable->height)
-    NoSelectionMade=FALSE;
-  /* Become aware of whether the user has made an active selection   */
-  /* This will become important later, when creating a reduced mask. */
+<tscreen><verb>
+void gtk_selection_add_handler( GtkWidget            *widget, 
+                                GdkAtom               selection,
+                                GdkAtom               target,
+                                GtkSelectionFunction  function,
+                                GtkRemoveFunction     remove_func,
+                                gpointer              data );
+</verb></tscreen>
 
-  /* If we want to preview the entire image, overrule the above!  */
-  /* Of course, if no selection has been made, this does nothing! */
-  if (Selection==ENTIRE_IMAGE) {
-    x1=0;
-    x2=drawable->width;
-    y1=0;
-    y2=drawable->height;
-  }
+<tt/widget/, <tt/selection/, and <tt/target/ identify the requests
+this handler will manage.  <tt/remove_func/, if not
+NULL, will be called when the signal handler is removed. This is
+useful, for instance, for interpreted languages which need to
+keep track of a reference count for <tt/data/.
 
-  /* If we want to preview a selection with some surronding area we */
-  /* have to expand it a little bit. Consider it a bit of a riddle. */
-  if (Selection==SELECTION_IN_CONTEXT) {
-    x1=MAX(0,                x1-width/2.0);
-    x2=MIN(drawable->width,  x2+width/2.0);
-    y1=MAX(0,                y1-height/2.0);
-    y2=MIN(drawable->height, y2+height/2.0);
-  }
+The callback function has the signature:
 
-  /* How we can determine the width and the height of the area being */
-  /* reduced.                                                        */
-  width  = x2-x1;
-  height = y2-y1;
+<tscreen><verb>
+typedef void (*GtkSelectionFunction)( GtkWidget        *widget, 
+                                      GtkSelectionData *selection_data,
+                                      gpointer          data );
 
-  /* The lines below determine which dimension is to be the longer   */
-  /* side. The idea borrowed from the supernova plug-in. I suspect I */
-  /* could've thought of it myself, but the truth must be told.      */
-  /* Plagiarism stinks!                                               */
-  if (width>height) {
-    RW=LongerSize;
-    RH=(float) height * (float) LongerSize/ (float) width;
-  }
-  else {
-    RH=LongerSize;
-    RW=(float)width * (float) LongerSize/ (float) height;
-  }
+</verb></tscreen>
 
-  /* The intire image is stretched into a string! */
-  tempRGB   = (guchar *) malloc(RW*RH*bytes);
-  tempmask  = (guchar *) malloc(RW*RH);
+The GtkSelectionData is the same as above, but this time, we're
+responsible for filling in the fields <tt/type/, <tt/format/,
+<tt/data/, and <tt/length/. (The <tt/format/ field is actually
+important here - the X server uses it to figure out whether the data
+needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
+character - or 32 - <em/i.e./ a. integer.) This is done by calling the
+function:
 
-  gimp_pixel_rgn_init (&amp;srcPR, drawable, x1, y1, width, height, FALSE, FALSE);
-  gimp_pixel_rgn_init (&amp;srcMask, mask, x1, y1, width, height, FALSE, FALSE);
+<tscreen><verb>
+void gtk_selection_data_set( GtkSelectionData *selection_data,
+                             GdkAtom           type,
+                             gint              format,
+                             guchar           *data,
+                             gint              length );
+</verb></tscreen>
 
-  /* Grab enough to save a row of image and a row of mask. */
-  src_row       = (guchar *) malloc (width*bytes);
-  src_mask_row  = (guchar *) malloc (width);
+This function takes care of properly making a copy of the data so that
+you don't have to worry about keeping it around. (You should not fill
+in the fields of the GtkSelectionData structure by hand.)
 
-  for (i=0; i < RH; i++) {
-    whichrow=(float)i*(float)height/(float)RH;
-    gimp_pixel_rgn_get_row (&amp;srcPR, src_row, x1, y1+whichrow, width);
-    gimp_pixel_rgn_get_row (&amp;srcMask, src_mask_row, x1, y1+whichrow, width);
+When prompted by the user, you claim ownership of the selection by
+calling:
 
-    for (j=0; j < RW; j++) {
-      whichcol=(float)j*(float)width/(float)RW;
+<tscreen><verb>
+gint gtk_selection_owner_set( GtkWidget *widget,
+                              GdkAtom    selection,
+                              guint32    time );
+</verb></tscreen>
 
-      /* No selection made = each point is completely selected! */
-      if (NoSelectionMade)
-        tempmask[i*RW+j]=255;
-      else
-        tempmask[i*RW+j]=src_mask_row[whichcol];
+If another application claims ownership of the selection, you will
+receive a "selection_clear_event".
 
-      /* Add the row to the one long string which now contains the image! */
-      tempRGB[i*RW*bytes+j*bytes+0]=src_row[whichcol*bytes+0];
-      tempRGB[i*RW*bytes+j*bytes+1]=src_row[whichcol*bytes+1];
-      tempRGB[i*RW*bytes+j*bytes+2]=src_row[whichcol*bytes+2];
+As an example of supplying the selection, the following program adds
+selection functionality to a toggle button. When the toggle button is
+depressed, the program claims the primary selection. The only target
+supported (aside from certain targets like "TARGETS" supplied by GTK
+itself), is the "STRING" target. When this target is requested, a
+string representation of the time is returned.
 
-      /* Hold on to the alpha as well */
-      if (bytes==4)
-        tempRGB[i*RW*bytes+j*bytes+3]=src_row[whichcol*bytes+3];
-    }
-  }
-  temp->bpp=bytes;
-  temp->width=RW;
-  temp->height=RH;
-  temp->rgb=tempRGB;
-  temp->mask=tempmask;
-  return temp;
-}
+<tscreen><verb>
+/* example-start selection setselection.c */
 
-The following is a preview function which used the same ReducedImage type!
-Note that it uses fakes transparancy (if one is present by means of
-fake_transparancy which is defined as follows:
+#include <gtk/gtk.h>
+#include <time.h>
 
-gint fake_transparency(gint i, gint j)
+/* Callback when the user toggles the selection */
+void
+selection_toggled (GtkWidget *widget, gint *have_selection)
 {
-  if ( ((i%20)- 10) * ((j%20)- 10)>0   )
-    return 64;
+  if (GTK_TOGGLE_BUTTON(widget)->active)
+    {
+      *have_selection = gtk_selection_owner_set (widget,
+                                                GDK_SELECTION_PRIMARY,
+                                                GDK_CURRENT_TIME);
+      /* if claiming the selection failed, we return the button to
+        the out state */
+      if (!*have_selection)
+       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
+    }
   else
-    return 196;
+    {
+      if (*have_selection)
+       {
+         /* Before clearing the selection by setting the owner to NULL,
+            we check if we are the actual owner */
+         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
+           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
+                                    GDK_CURRENT_TIME);
+         *have_selection = FALSE;
+       }
+    }
 }
 
-Now here's the preview function:
-
-void
-my_preview_render_function(GtkWidget     *preview,
-                           gint          changewhat,
-                           gint          changewhich)
+/* Called when another application claims the selection */
+gint
+selection_clear (GtkWidget *widget, GdkEventSelection *event,
+                gint *have_selection)
 {
-  gint Inten, bytes=drawable->bpp;
-  gint i, j, k;
-  float partial;
-  gint RW=reduced->width;
-  gint RH=reduced->height;
-  guchar *row=malloc(bytes*RW);;
-
+  *have_selection = FALSE;
+  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
 
-  for (i=0; i < RH; i++) {
-    for (j=0; j < RW; j++) {
+  return TRUE;
+}
 
-      row[j*3+0] = reduced->rgb[i*RW*bytes + j*bytes + 0];
-      row[j*3+1] = reduced->rgb[i*RW*bytes + j*bytes + 1];
-      row[j*3+2] = reduced->rgb[i*RW*bytes + j*bytes + 2];
+/* Supplies the current time as the selection. */
+void
+selection_handle (GtkWidget *widget, 
+                 GtkSelectionData *selection_data,
+                 gpointer data)
+{
+  gchar *timestr;
+  time_t current_time;
 
-      if (bytes==4)
-        for (k=0; k<3; k++) {
-          float transp=reduced->rgb[i*RW*bytes+j*bytes+3]/255.0;
-          row[3*j+k]=transp*a[3*j+k]+(1-transp)*fake_transparency(i,j);
-        }
-    }
-    gtk_preview_draw_row( GTK_PREVIEW(preview),row,0,i,RW);
-  }
+  current_time = time (NULL);
+  timestr = asctime (localtime(&amp;current_time)); 
+  /* When we return a single string, it should not be null terminated.
+     That will be done for us */
 
-  free(a);
-  gtk_widget_draw(preview,NULL);
-  gdk_flush();
+  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
+                         8, timestr, strlen(timestr));
 }
 
-Applicable Routines
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
 
-guint           gtk_preview_get_type           (void);
-/* No idea */
-void            gtk_preview_uninit             (void);
-/* No idea */
-GtkWidget*      gtk_preview_new                (GtkPreviewType   type);
-/* Described above */
-void            gtk_preview_size               (GtkPreview      *preview,
-                                                gint             width,
-                                                gint             height);
-/* Allows you to resize an existing preview.    */
-/* Apparantly there's a bug in GTK which makes  */
-/* this process messy. A way to clean up a mess */
-/* is to manually resize the window containing  */
-/* the preview after resizing the preview.      */
+  GtkWidget *selection_button;
 
-void            gtk_preview_put                (GtkPreview      *preview,
-                                                GdkWindow       *window,
-                                                GdkGC           *gc,
-                                                gint             srcx,
-                                                gint             srcy,
-                                                gint             destx,
-                                                gint             desty,
-                                                gint             width,
-                                                gint             height);
-/* No idea */
+  static int have_selection = FALSE;
+  
+  gtk_init (&amp;argc, &amp;argv);
 
-void            gtk_preview_put_row            (GtkPreview      *preview,
-                                                guchar          *src,
-                                                guchar          *dest,
-                                                gint             x,
-                                                gint             y,
-                                                gint             w);
-/* No idea */
+  /* Create the toplevel window */
 
-void            gtk_preview_draw_row           (GtkPreview      *preview,
-                                                guchar          *data,
-                                                gint             x,
-                                                gint             y,
-                                                gint             w);
-/* Described in the text */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
 
-void            gtk_preview_set_expand         (GtkPreview      *preview,
-                                                gint             expand);
-/* No idea */
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+
+  /* Create a toggle button to act as the selection */
 
-/* No clue for any of the below but    */
-/* should be standard for most widgets */
-void            gtk_preview_set_gamma          (double           gamma);
-void            gtk_preview_set_color_cube     (guint            nred_shades,
-                                                guint            ngreen_shades,
-                                                guint            nblue_shades,
-                                                guint            ngray_shades);
-void            gtk_preview_set_install_cmap   (gint             install_cmap);
-void            gtk_preview_set_reserved       (gint             nreserved);
-GdkVisual*      gtk_preview_get_visual         (void);
-GdkColormap*    gtk_preview_get_cmap           (void);
-GtkPreviewInfo* gtk_preview_get_info           (void);
+  selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
+  gtk_container_add (GTK_CONTAINER (window), selection_button);
+  gtk_widget_show (selection_button);
 
-That's all, folks!
+  gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
+                     GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
+  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
+                     GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
+
+  gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
+                            GDK_SELECTION_TYPE_STRING,
+                            selection_handle, NULL);
 
+  gtk_widget_show (selection_button);
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
+/* example-end */
 </verb></tscreen>
 
+
 <!-- ***************************************************************** -->
-<sect>The EventBox Widget<label id="sec_The_EventBox_Widget">
+<sect>glib<label id="sec_glib">
 <!-- ***************************************************************** -->
-<p> 
-Some gtk widgets don't have associated X windows, so they just draw on 
-their parents. Because of this, they cannot recieve events
-and if they are incorrectly sized, they don't clip so you can get
-messy overwritting etc. If you require more from these widgets, the
-EventBox is for you.
-
-At first glance, the EventBox widget might appear to be totally
-useless. It draws nothing on the screen and responds to no
-events. However, it does serve a function - it provides an X window for
-its child widget. This is important as many GTK widgets do not
-have an associated X window. Not having an X window saves memory and
-improves performance, but also has some drawbacks. A widget without an
-X window cannot receive events, and does not perform any clipping on
-it's contents. Although the name <em/EventBox/ emphasizes the
-event-handling function, the widget can also be used for clipping. 
-(And more ... see the example below.)
+<p>
+glib provides many useful functions and definitions available for use
+when creating GDK and GTK applications. I will list them all here with
+a brief explanation. Many are duplicates of standard libc functions so
+I won't go into detail on those. This is mostly to be used as a reference,
+so you know what is available for use.
 
-To create a new EventBox widget, use:
+<!-- ----------------------------------------------------------------- -->
+<sect1>Definitions
+<p>
+Definitions for the extremes of many of the standard types are:
 
 <tscreen><verb>
-GtkWidget *gtk_event_box_new( void );
+G_MINFLOAT
+G_MAXFLOAT
+G_MINDOUBLE
+G_MAXDOUBLE
+G_MINSHORT
+G_MAXSHORT
+G_MININT
+G_MAXINT
+G_MINLONG
+G_MAXLONG
 </verb></tscreen>
 
-A child widget can then be added to this EventBox:
+Also, the following typedefs. The ones left unspecified are dynamically set
+depending on the architecture. Remember to avoid counting on the size of a
+pointer if you want to be portable! Eg, a pointer on an Alpha is 8 bytes, but 4
+on Intel.
 
 <tscreen><verb>
-gtk_container_add( GTK_CONTAINER(event_box), widget );
-</verb></tscreen>
+char   gchar;
+short  gshort;
+long   glong;
+int    gint;
+char   gboolean;
 
-The following example demonstrates both uses of an EventBox - a label
-is created that is clipped to a small box, and set up so that a
-mouse-click on the label causes the program to exit.
+unsigned char   guchar;
+unsigned short  gushort;
+unsigned long   gulong;
+unsigned int    guint;
 
-<tscreen><verb>
-/* example-start eventbox eventbox.c */
+float   gfloat;
+double  gdouble;
+long double gldouble;
 
-#include <gtk/gtk.h>
+void* gpointer;
 
-int 
-main (int argc, char *argv[])
-{
-    GtkWidget *window;
-    GtkWidget *event_box;
-    GtkWidget *label;
-    
-    gtk_init (&amp;argc, &amp;argv);
-    
-    window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-    
-    gtk_window_set_title (GTK_WINDOW (window), "Event Box");
-    
-    gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
-    
-    gtk_container_border_width (GTK_CONTAINER (window), 10);
-    
-    /* Create an EventBox and add it to our toplevel window */
-    
-    event_box = gtk_event_box_new ();
-    gtk_container_add (GTK_CONTAINER(window), event_box);
-    gtk_widget_show (event_box);
-    
-    /* Create a long label */
-    
-    label = gtk_label_new ("Click here to quit, quit, quit, quit, quit");
-    gtk_container_add (GTK_CONTAINER (event_box), label);
-    gtk_widget_show (label);
-    
-    /* Clip it short. */
-    gtk_widget_set_usize (label, 110, 20);
-    
-    /* And bind an action to it */
-    gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK);
-    gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event",
-                       GTK_SIGNAL_FUNC (gtk_exit), NULL);
-    
-    /* Yet one more thing you need an X window for ... */
-    
-    gtk_widget_realize (event_box);
-    gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1));
-    
-    gtk_widget_show (window);
-    
-    gtk_main ();
-    
-    return 0;
-}
-/* example-end */
+gint8
+guint8
+gint16
+guint16
+gint32
+guint32
 </verb></tscreen>
 
-<!-- ***************************************************************** -->
-<sect>Setting Widget Attributes<label id="sec_setting_widget_attributes">
-<!-- ***************************************************************** -->
+<!-- ----------------------------------------------------------------- -->
+<sect1>Doubly Linked Lists
 <p>
-This describes the functions used to operate on widgets.  These can be used
-to set style, padding, size etc.
-
-(Maybe I should make a whole section on accelerators.)
+The following functions are used to create, manage, and destroy doubly
+linked lists.  I assume you know what linked lists are, as it is beyond the scope
+of this document to explain them.  Of course, it's not required that you
+know these for general use of GTK, but they are nice to know.
 
 <tscreen><verb>
-void gtk_widget_install_accelerator( GtkWidget           *widget,
-                                     GtkAcceleratorTable *table,
-                                     gchar               *signal_name,
-                                     gchar                key,
-                                     guint8               modifiers );
+GList *g_list_alloc( void );
 
-void gtk_widget_remove_accelerator ( GtkWidget           *widget,
-                                     GtkAcceleratorTable *table,
-                                     gchar               *signal_name);
+void g_list_free( GList *list );
 
-void gtk_widget_activate( GtkWidget *widget );
+void g_list_free_1( GList *list );
 
-void gtk_widget_set_name( GtkWidget *widget,
-                          gchar     *name );
+GList *g_list_append( GList     *list,
+                      gpointer   data );
+                          
+GList *g_list_prepend( GList    *list,
+                       gpointer  data );
+                       
+GList *g_list_insert( GList    *list,
+                      gpointer  data,
+                           gint      position );
 
-gchar *gtk_widget_get_name( GtkWidget *widget );
+GList *g_list_remove( GList    *list,
+                      gpointer  data );
+                          
+GList *g_list_remove_link( GList *list,
+                           GList *link );
 
-void gtk_widget_set_sensitive( GtkWidget *widget,
-                               gint       sensitive );
+GList *g_list_reverse( GList *list );
+
+GList *g_list_nth( GList *list,
+                   gint   n );
+                          
+GList *g_list_find( GList    *list,
+                    gpointer  data );
+
+GList *g_list_last( GList *list );
+
+GList *g_list_first( GList *list );
+
+gint g_list_length( GList *list );
+
+void g_list_foreach( GList    *list,
+                     GFunc     func,
+                     gpointer  user_data );
+</verb></tscreen>                                            
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Singly Linked Lists
+<p>
+Many of the above functions for singly linked lists are identical to the
+above. Here is a complete list:
+<tscreen><verb>
+GSList *g_slist_alloc( void );
+
+void g_slist_free( GSList *list );
+
+void g_slist_free_1( GSList *list );
+
+GSList *g_slist_append( GSList   *list,
+                        gpointer  data );
+               
+GSList *g_slist_prepend( GSList   *list,
+                         gpointer  data );
+                            
+GSList *g_slist_insert( GSList   *list,
+                        gpointer  data,
+                           gint      position );
+                            
+GSList *g_slist_remove( GSList   *list,
+                        gpointer  data );
+                            
+GSList *g_slist_remove_link( GSList *list,
+                             GSList *link );
+                            
+GSList *g_slist_reverse( GSList *list );
+
+GSList *g_slist_nth( GSList *list,
+                     gint    n );
+                            
+GSList *g_slist_find( GSList   *list,
+                      gpointer  data );
+                            
+GSList *g_slist_last( GSList *list );
 
-void gtk_widget_set_style( GtkWidget *widget,
-                           GtkStyle  *style );
-                                          
-GtkStyle *gtk_widget_get_style( GtkWidget *widget );
+gint g_slist_length( GSList *list );
 
-GtkStyle *gtk_widget_get_default_style( void );
+void g_slist_foreach( GSList   *list,
+                      GFunc     func,
+                           gpointer  user_data );
+       
+</verb></tscreen>
 
-void gtk_widget_set_uposition( GtkWidget *widget,
-                               gint       x,
-                               gint       y );
+<!-- ----------------------------------------------------------------- -->
+<sect1>Memory Management
+<p>
+<tscreen><verb>
+gpointer g_malloc( gulong size );
+</verb></tscreen>
 
-void gtk_widget_set_usize( GtkWidget *widget,
-                           gint       width,
-                           gint       height );
+This is a replacement for malloc(). You do not need to check the return
+vaule as it is done for you in this function.
 
-void gtk_widget_grab_focus( GtkWidget *widget );
+<tscreen><verb>
+gpointer g_malloc0( gulong size );
+</verb></tscreen>
 
-void gtk_widget_show( GtkWidget *widget );
+Same as above, but zeroes the memory before returning a pointer to it.
 
-void gtk_widget_hide( GtkWidget *widget );
+<tscreen><verb>
+gpointer g_realloc( gpointer mem,
+                    gulong   size );
 </verb></tscreen>
 
-<!-- ***************************************************************** -->
-<sect>Timeouts, IO and Idle Functions<label id="sec_timeouts">
-<!-- ***************************************************************** -->
-
-<!-- ----------------------------------------------------------------- -->
-<sect1>Timeouts
-<p>
-You may be wondering how you make GTK do useful work when in gtk_main.
-Well, you have several options. Using the following functions you can
-create a timeout function that will be called every "interval"
-milliseconds.
+Relocates "size" bytes of memory starting at "mem".  Obviously, the
+memory should have been previously allocated.
 
 <tscreen><verb>
-gint gtk_timeout_add( guint32     interval,
-                      GtkFunction function,
-                      gpointer    data );
+void g_free( gpointer mem );
 </verb></tscreen>
 
-The first argument is the number of milliseconds between calls to your
-function.  The second argument is the function you wish to have called, and
-the third, the data passed to this callback function. The return value is
-an integer "tag" which may be used to stop the timeout by calling:
+Frees memory. Easy one.
 
 <tscreen><verb>
-void gtk_timeout_remove( gint tag );
+void g_mem_profile( void );
 </verb></tscreen>
 
-You may also stop the timeout function by returning zero or FALSE from
-your callback function. Obviously this means if you want your function to
-continue to be called, it should return a non-zero value, ie TRUE.
-
-The declaration of your callback should look something like this:
+Dumps a profile of used memory, but requries that you add #define
+MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
 
 <tscreen><verb>
-gint timeout_callback( gpointer data );
+void g_mem_check( gpointer mem );
 </verb></tscreen>
 
+Checks that a memory location is valid.  Requires you add #define
+MEM_CHECK to the top of gmem.c and re-make and make install.
+
 <!-- ----------------------------------------------------------------- -->
-<sect1>Monitoring IO
+<sect1>Timers
 <p>
-Another nifty feature of GTK, is the ability to have it check for data on a
-file descriptor for you (as returned by open(2) or socket(2)). This is
-especially useful for networking applications. The function:
+Timer functions..
 
 <tscreen><verb>
-gint gdk_input_add( gint              source,
-                    GdkInputCondition condition,
-                    GdkInputFunction  function,
-                    gpointer          data );
-</verb></tscreen>
-
-Where the first argument is the file descriptor you wish to have watched,
-and the second specifies what you want GDK to look for.  This may be one of:
+GTimer *g_timer_new( void );
 
-<itemize>
-<item>GDK_INPUT_READ - Call your function when there is data ready for
-reading on your file descriptor.
+void g_timer_destroy( GTimer *timer );
 
-<item>GDK_INPUT_WRITE - Call your function when the file descriptor is
-ready for writing.
-</itemize>
+void g_timer_start( GTimer  *timer );
 
-As I'm sure you've figured out already, the third argument is the function
-you wish to have called when the above conditions are satisfied, and the
-fourth is the data to pass to this function.
+void g_timer_stop( GTimer  *timer );
 
-The return value is a tag that may be used to stop GDK from monitoring this
-file descriptor using the following function.
+void g_timer_reset( GTimer  *timer );
 
-<tscreen><verb>
-void gdk_input_remove( gint tag );
-</verb></tscreen>
+gdouble g_timer_elapsed( GTimer *timer,
+                         gulong *microseconds );
+</verb></tscreen>                       
 
-The callback function should be declared as:
+<!-- ----------------------------------------------------------------- -->
+<sect1>String Handling
+<p>
+A whole mess of string handling functions. They all look very interesting, and
+probably better for many purposes than the standard C string functions, but
+require documentation.
 
 <tscreen><verb>
-void input_callback( gpointer          data,
-                     gint              source, 
-                     GdkInputCondition condition );
-</verb></tscreen>
+GString *g_string_new( gchar *init );
 
-Where <tt/source/ and <tt/condition/ are as specified above.
+void g_string_free( GString *string,
+                    gint     free_segment );
+                            
+GString *g_string_assign( GString *lval,
+                          gchar   *rval );
+                            
+GString *g_string_truncate( GString *string,
+                            gint     len );
+                            
+GString *g_string_append( GString *string,
+                          gchar   *val );
+                           
+GString *g_string_append_c( GString *string,
+                            gchar    c );
+       
+GString *g_string_prepend( GString *string,
+                           gchar   *val );
+                            
+GString *g_string_prepend_c( GString *string,
+                             gchar    c );
+       
+void g_string_sprintf( GString *string,
+                       gchar   *fmt,
+                       ...);
+       
+void g_string_sprintfa ( GString *string,
+                         gchar   *fmt,
+                         ... );
+</verb></tscreen>                                                        
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Idle Functions
+<sect1>Utility and Error Functions
 <p>
-<!-- Need to check on idle priorities - TRG -->
-What if you have a function you want called when nothing else is
-happening ?
-
 <tscreen><verb>
-gint gtk_idle_add( GtkFunction function,
-                   gpointer    data );
+gchar *g_strdup( const gchar *str );
 </verb></tscreen>
 
-This causes GTK to call the specified function whenever nothing else is
-happening.
+Replacement strdup function.  Copies the original strings contents to
+newly allocated memory, and returns a pointer to it.
 
 <tscreen><verb>
-void gtk_idle_remove( gint tag );
+gchar *g_strerror( gint errnum );
 </verb></tscreen>
 
-I won't explain the meaning of the arguments as they follow very much like
-the ones above. The function pointed to by the first argument to
-gtk_idle_add will be called whenever the opportunity arises. As with the
-others, returning FALSE will stop the idle function from being called.
+I recommend using this for all error messages.  It's much nicer, and more
+portable than perror() or others.  The output is usually of the form:
 
-<!-- ***************************************************************** -->
-<sect>Managing Selections
-<!-- ***************************************************************** -->
+<tscreen><verb>
+program name:function that failed:file or further description:strerror
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Overview
-<p>
-One type of interprocess communication supported by GTK is
-<em>selections</em>. A selection identifies a chunk of data, for
-instance, a portion of text, selected by the user in some fashion, for
-instance, by dragging with the mouse. Only one application on a
-display, (the <em>owner</em> can own a particular selection at one
-time, so when a selection is claimed by one application, the previous
-owner must indicate to the user that selection has been
-relinquished. Other applications can request the contents of a
-selection in different forms, called <em>targets</em>. There can be
-any number of selections, but most X applications only handle one, the
-<em>primary selection</em>.
+Here's an example of one such call used in our hello_world program:
 
-In most cases, it isn't necessary for a GTK application to deal with
-selections itself. The standard widgets, such as the Entry widget,
-already have the capability to claim the selection when appropriate
-(e.g., when the user drags over text), and to retrieve the contents of
-the selection owned by another widget, or another application (e.g.,
-when the user clicks the second mouse button). However, there may be
-cases in which you want to give other widgets the ability to supply
-the selection, or you wish to retrieve targets not supported by
-default.
+<tscreen><verb>
+g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
+</verb></tscreen>
 
-A fundamental concept needed to understand selection handling is that
-of the <em>atom</em>. An atom is an integer that uniquely identifies a
-string (on a certain display). Certain atoms are predefined by the X
-server, and in some cases there are constants in <tt>gtk.h</tt>
-corresponding to these atoms. For instance the constant
-<tt>GDK_PRIMARY_SELECTION</tt> corresponds to the string "PRIMARY".
-In other cases, you should use the functions
-<tt>gdk_atom_intern()</tt>, to get the atom corresponding to a string,
-and <tt>gdk_atom_name()</tt>, to get the name of an atom. Both
-selections and targets are identifed by atoms.
+<tscreen><verb>
+void g_error( gchar *format, ... );
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Retrieving the selection
-<p>
-Retrieving the selection is an asynchronous process. To start the
-process, you call:
+Prints an error message. The format is just like printf, but it
+prepends "** ERROR **: " to your message, and exits the program.  
+Use only for fatal errors.
 
 <tscreen><verb>
-gint gtk_selection_convert( GtkWidget *widget, 
-                            GdkAtom    selection, 
-                            GdkAtom    target,
-                            guint32    time );
-</verb</tscreen>
-
-This <em>converts</em> the selection into the form specified by
-<tt/target/. If at all possible, the time field should be the time
-from the event that triggered the selection. This helps make sure that
-events occur in the order that the user requested them. However, if it
-is not available (for instance, if the conversion was triggered by
-a "clicked" signal), then you can use the constant
-<tt>GDK_CURRENT_TIME</tt>.
+void g_warning( gchar *format, ... );
+</verb></tscreen>
 
-When the selection owner responds to the request, a
-"selection_received" signal is sent to your application. The handler
-for this signal receives a pointer to a <tt>GtkSelectionData</tt>
-structure, which is defined as:
+Same as above, but prepends "** WARNING **: ", and does not exit the
+program.
 
 <tscreen><verb>
-struct _GtkSelectionData
-{
-  GdkAtom selection;
-  GdkAtom target;
-  GdkAtom type;
-  gint    format;
-  guchar *data;
-  gint    length;
-};
+void g_message( gchar *format, ... );
+</verb></tscreen>
+
+Prints "message: " prepended to the string you pass in.
+
+<tscreen><verb>
+void g_print( gchar *format, ... );
 </verb></tscreen>
 
-<tt>selection</tt> and <tt>target</tt> are the values you gave in your
-<tt>gtk_selection_convert()</tt> call. <tt>type</tt> is an atom that
-identifies the type of data returned by the selection owner. Some
-possible values are "STRING", a string of latin-1 characters, "ATOM",
-a series of atoms, "INTEGER", an integer, etc. Most targets can only
-return one type. <tt/format/ gives the length of the units (for
-instance characters) in bits. Usually, you don't care about this when
-receiving data. <tt>data</tt> is a pointer to the returned data, and
-<tt>length</tt> gives the length of the returned data, in bytes. If
-<tt>length</tt> is negative, then an error occurred and the selection
-could not be retrieved. This might happen if no application owned the
-selection, or if you requested a target that the application didn't
-support. The buffer is actually guaranteed to be one byte longer than
-<tt>length</tt>; the extra byte will always be zero, so it isn't
-necessary to make a copy of strings just to null terminate them.
+Replacement for printf().
 
-In the following example, we retrieve the special target "TARGETS",
-which is a list of all targets into which the selection can be
-converted.
+And our last function:
 
 <tscreen><verb>
-/* example-start selection gettargets.c */
-
-#include <gtk/gtk.h>
+gchar *g_strsignal( gint signum );
+</verb></tscreen>
 
-void selection_received (GtkWidget *widget, 
-                        GtkSelectionData *selection_data, 
-                        gpointer data);
+Prints out the name of the Unix system signal given the signal number.
+Useful in generic signal handling functions.
 
-/* Signal handler invoked when user clicks on the "Get Targets" button */
-void
-get_targets (GtkWidget *widget, gpointer data)
-{
-  static GdkAtom targets_atom = GDK_NONE;
+All of the above are more or less just stolen from glib.h.  If anyone cares
+to document any function, just send me an email!
 
-  /* Get the atom corresonding to the string "TARGETS" */
-  if (targets_atom == GDK_NONE)
-    targets_atom = gdk_atom_intern ("TARGETS", FALSE);
+<!-- ***************************************************************** -->
+<sect>GTK's rc Files
+<!-- ***************************************************************** -->
+<p>
+GTK has it's own way of dealing with application defaults, by using rc
+files. These can be used to set the colors of just about any widget, and
+can also be used to tile pixmaps onto the background of some widgets.  
 
-  /* And request the "TARGETS" target for the primary selection */
-  gtk_selection_convert (widget, GDK_SELECTION_PRIMARY, targets_atom,
-                        GDK_CURRENT_TIME);
-}
+<!-- ----------------------------------------------------------------- -->
+<sect1>Functions For rc Files 
+<p>
+When your application starts, you should include a call to:
 
-/* Signal handler called when the selections owner returns the data */
-void
-selection_received (GtkWidget *widget, GtkSelectionData *selection_data, 
-                   gpointer data)
-{
-  GdkAtom *atoms;
-  GList *item_list;
-  int i;
+<tscreen><verb>
+void gtk_rc_parse( char *filename );
+</verb></tscreen>
 
-  /* **** IMPORTANT **** Check to see if retrieval succeeded  */
-  if (selection_data->length < 0)
-    {
-      g_print ("Selection retrieval failed\n");
-      return;
-    }
-  /* Make sure we got the data in the expected form */
-  if (selection_data->type != GDK_SELECTION_TYPE_ATOM)
-    {
-      g_print ("Selection \"TARGETS\" was not returned as atoms!\n");
-      return;
-    }
-  
-  /* Print out the atoms we received */
-  atoms = (GdkAtom *)selection_data->data;
+Passing in the filename of your rc file.  This will cause GTK to parse this
+file, and use the style settings for the widget types defined there.
 
-  item_list = NULL;
-  for (i=0; i<selection_data->length/sizeof(GdkAtom); i++)
-    {
-      char *name;
-      name = gdk_atom_name (atoms[i]);
-      if (name != NULL)
-       g_print ("%s\n",name);
-      else
-       g_print ("(bad atom)\n");
-    }
+If you wish to have a special set of widgets that can take on a different
+style from others, or any other logical division of widgets, use a call to:
 
-  return;
-}
+<tscreen><verb>
+void gtk_widget_set_name( GtkWidget *widget,
+                          gchar     *name );
+</verb></tscreen>
 
-int 
-main (int argc, char *argv[])
-{
-  GtkWidget *window;
-  GtkWidget *button;
-  
-  gtk_init (&amp;argc, &amp;argv);
+Passing your newly created widget as the first argument, and the name
+you wish to give it as the second. This will allow you to change the
+attributes of this widget by name through the rc file.
 
-  /* Create the toplevel window */
+If we use a call something like this:
 
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
-  gtk_container_border_width (GTK_CONTAINER (window), 10);
+<tscreen><verb>
+button = gtk_button_new_with_label ("Special Button");
+gtk_widget_set_name (button, "special button");
+</verb></tscreen>
 
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+Then this button is given the name "special button" and may be addressed by
+name in the rc file as "special button.GtkButton".  [<--- Verify ME!]
 
-  /* Create a button the user can click to get targets */
+The example rc file below, sets the properties of the main window, and lets
+all children of that main window inherit the style described by the "main
+button" style.  The code used in the application is:
 
-  button = gtk_button_new_with_label ("Get Targets");
-  gtk_container_add (GTK_CONTAINER (window), button);
+<tscreen><verb>
+window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+gtk_widget_set_name (window, "main window");
+</verb></tscreen>
 
-  gtk_signal_connect (GTK_OBJECT(button), "clicked",
-                     GTK_SIGNAL_FUNC (get_targets), NULL);
-  gtk_signal_connect (GTK_OBJECT(button), "selection_received",
-                     GTK_SIGNAL_FUNC (selection_received), NULL);
+And then the style is defined in the rc file using:
 
-  gtk_widget_show (button);
-  gtk_widget_show (window);
-  
-  gtk_main ();
-  
-  return 0;
-}
-/* example-end */
+<tscreen><verb>
+widget "main window.*GtkButton*" style "main_button"
 </verb></tscreen>
 
+Which sets all the GtkButton widgets in the "main window" to the
+"main_buttons" style as defined in the rc file.
+
+As you can see, this is a fairly powerful and flexible system.  Use your
+imagination as to how best to take advantage of this.
+
 <!-- ----------------------------------------------------------------- -->
-<sect1> Supplying the selection 
+<sect1>GTK's rc File Format
 <p>
-Supplying the selection is a bit more complicated. You must register 
-handlers that will be called when your selection is requested. For
-each selection/target pair you will handle, you make a call to:
+The format of the GTK file is illustrated in the example below. This is
+the testgtkrc file from the GTK distribution, but I've added a
+few comments and things. You may wish to include this explanation
+your application to allow the user to fine tune his application.
 
-<tscreen><verb>
-void gtk_selection_add_handler( GtkWidget            *widget, 
-                                GdkAtom               selection,
-                                GdkAtom               target,
-                                GtkSelectionFunction  function,
-                                GtkRemoveFunction     remove_func,
-                                gpointer              data );
-</verb></tscreen>
+There are several directives to change the attributes of a widget.
 
-<tt/widget/, <tt/selection/, and <tt/target/ identify the requests
-this handler will manage.  <tt/remove_func/, if not
-NULL, will be called when the signal handler is removed. This is
-useful, for instance, for interpreted languages which need to
-keep track of a reference count for <tt/data/.
+<itemize>
+<item>fg - Sets the foreground color of a widget.
+<item>bg - Sets the background color of a widget.
+<item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
+<item>font - Sets the font to be used with the given widget.
+</itemize>
 
-The callback function has the signature:
+In addition to this, there are several states a widget can be in, and you
+can set different colors, pixmaps and fonts for each state. These states are:
 
-<tscreen><verb>
-typedef void (*GtkSelectionFunction)( GtkWidget        *widget, 
-                                      GtkSelectionData *selection_data,
-                                      gpointer          data );
+<itemize>
+<item>NORMAL - The normal state of a widget, without the mouse over top of
+it, and not being pressed etc.
+<item>PRELIGHT - When the mouse is over top of the widget, colors defined
+using this state will be in effect.
+<item>ACTIVE - When the widget is pressed or clicked it will be active, and
+the attributes assigned by this tag will be in effect.
+<item>INSENSITIVE - When a widget is set insensitive, and cannot be
+activated, it will take these attributes.
+<item>SELECTED - When an object is selected, it takes these attributes.
+</itemize>
+
+When using the "fg" and "bg" keywords to set the colors of widgets, the
+format is:
 
+<tscreen><verb>
+fg[<STATE>] = { Red, Green, Blue }
 </verb></tscreen>
 
-The GtkSelectionData is the same as above, but this time, we're
-responsible for filling in the fields <tt/type/, <tt/format/,
-<tt/data/, and <tt/length/. (The <tt/format/ field is actually
-important here - the X server uses it to figure out whether the data
-needs to be byte-swapped or not. Usually it will be 8 - <em/i.e./ a
-character - or 32 - <em/i.e./ a. integer.) This is done by calling the
-function:
+Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
+Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
+white. They must be in float form, or they will register as 0, so a straight 
+"1" will not work, it must be "1.0".  A straight "0" is fine because it 
+doesn't matter if it's not recognized.  Unrecognized values are set to 0.
 
+bg_pixmap is very similar to the above, except the colors are replaced by a
+filename.
+
+pixmap_path is a list of paths seperated by ":"'s.  These paths will be
+searched for any pixmap you specify.
+
+The font directive is simply:
 <tscreen><verb>
-void gtk_selection_data_set( GtkSelectionData *selection_data,
-                             GdkAtom           type,
-                             gint              format,
-                             guchar           *data,
-                             gint              length );
+font = "<font name>"
 </verb></tscreen>
 
-This function takes care of properly making a copy of the data so that
-you don't have to worry about keeping it around. (You should not fill
-in the fields of the GtkSelectionData structure by hand.)
+Where the only hard part is figuring out the font string. Using xfontsel or
+similar utility should help.
+
+The "widget_class" sets the style of a class of widgets. These classes are
+listed in the widget overview on the class hierarchy.
+
+The "widget" directive sets a specificaly named set of widgets to a
+given style, overriding any style set for the given widget class.
+These widgets are registered inside the application using the
+gtk_widget_set_name() call. This allows you to specify the attributes of a
+widget on a per widget basis, rather than setting the attributes of an
+entire widget class. I urge you to document any of these special widgets so
+users may customize them.
+
+When the keyword <tt>parent</> is used as an attribute, the widget will take on
+the attributes of it's parent in the application.
 
-When prompted by the user, you claim ownership of the selection by
-calling:
+When defining a style, you may assign the attributes of a previously defined
+style to this new one.
 
 <tscreen><verb>
-gint gtk_selection_owner_set( GtkWidget *widget,
-                              GdkAtom    selection,
-                              guint32    time );
+style "main_button" = "button"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+  bg[PRELIGHT] = { 0.75, 0, 0 }
+}
 </verb></tscreen>
 
-If another application claims ownership of the selection, you will
-receive a "selection_clear_event".
+This example takes the "button" style, and creates a new "main_button" style
+simply by changing the font and prelight background color of the "button"
+style.
 
-As an example of supplying the selection, the following program adds
-selection functionality to a toggle button. When the toggle button is
-depressed, the program claims the primary selection. The only target
-supported (aside from certain targets like "TARGETS" supplied by GTK
-itself), is the "STRING" target. When this target is requested, a
-string representation of the time is returned.
+Of course, many of these attributes don't apply to all widgets. It's a
+simple matter of common sense really. Anything that could apply, should.
+
+<!-- ----------------------------------------------------------------- -->
+<sect1>Example rc file
+<p>
 
 <tscreen><verb>
-/* example-start selection setselection.c */
+# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
+#
+pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
+#
+# style <name> [= <name>]
+# {
+#   <option>
+# }
+#
+# widget <widget_set> style <style_name>
+# widget_class <widget_class_set> style <style_name>
 
-#include <gtk/gtk.h>
-#include <time.h>
 
-/* Callback when the user toggles the selection */
-void
-selection_toggled (GtkWidget *widget, gint *have_selection)
+# Here is a list of all the possible states.  Note that some do not apply to
+# certain widgets.
+#
+# NORMAL - The normal state of a widget, without the mouse over top of
+# it, and not being pressed etc.
+#
+# PRELIGHT - When the mouse is over top of the widget, colors defined
+# using this state will be in effect.
+#
+# ACTIVE - When the widget is pressed or clicked it will be active, and
+# the attributes assigned by this tag will be in effect.
+#
+# INSENSITIVE - When a widget is set insensitive, and cannot be
+# activated, it will take these attributes.
+#
+# SELECTED - When an object is selected, it takes these attributes.
+#
+# Given these states, we can set the attributes of the widgets in each of
+# these states using the following directives.
+#
+# fg - Sets the foreground color of a widget.
+# fg - Sets the background color of a widget.
+# bg_pixmap - Sets the background of a widget to a tiled pixmap.
+# font - Sets the font to be used with the given widget.
+#
+
+# This sets a style called "button".  The name is not really important, as
+# it is assigned to the actual widgets at the bottom of the file.
+
+style "window"
 {
-  if (GTK_TOGGLE_BUTTON(widget)->active)
-    {
-      *have_selection = gtk_selection_owner_set (widget,
-                                                GDK_SELECTION_PRIMARY,
-                                                GDK_CURRENT_TIME);
-      /* if claiming the selection failed, we return the button to
-        the out state */
-      if (!*have_selection)
-       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
-    }
-  else
-    {
-      if (*have_selection)
-       {
-         /* Before clearing the selection by setting the owner to NULL,
-            we check if we are the actual owner */
-         if (gdk_selection_owner_get (GDK_SELECTION_PRIMARY) == widget->window)
-           gtk_selection_owner_set (NULL, GDK_SELECTION_PRIMARY,
-                                    GDK_CURRENT_TIME);
-         *have_selection = FALSE;
-       }
-    }
+  #This sets the padding around the window to the pixmap specified.
+  #bg_pixmap[<STATE>] = "<pixmap filename>"
+  bg_pixmap[NORMAL] = "warning.xpm"
 }
 
-/* Called when another application claims the selection */
-gint
-selection_clear (GtkWidget *widget, GdkEventSelection *event,
-                gint *have_selection)
+style "scale"
 {
-  *have_selection = FALSE;
-  gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON(widget), FALSE);
-
-  return TRUE;
+  #Sets the foreground color (font color) to red when in the "NORMAL"
+  #state.
+  
+  fg[NORMAL] = { 1.0, 0, 0 }
+  
+  #Sets the background pixmap of this widget to that of it's parent.
+  bg_pixmap[NORMAL] = "<parent>"
 }
 
-/* Supplies the current time as the selection. */
-void
-selection_handle (GtkWidget *widget, 
-                 GtkSelectionData *selection_data,
-                 gpointer data)
+style "button"
 {
-  gchar *timestr;
-  time_t current_time;
+  # This shows all the possible states for a button.  The only one that
+  # doesn't apply is the SELECTED state.
+  
+  fg[PRELIGHT] = { 0, 1.0, 1.0 }
+  bg[PRELIGHT] = { 0, 0, 1.0 }
+  bg[ACTIVE] = { 1.0, 0, 0 }
+  fg[ACTIVE] = { 0, 1.0, 0 }
+  bg[NORMAL] = { 1.0, 1.0, 0 }
+  fg[NORMAL] = { .99, 0, .99 }
+  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
+  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
+}
 
-  current_time = time (NULL);
-  timestr = asctime (localtime(&amp;current_time)); 
-  /* When we return a single string, it should not be null terminated.
-     That will be done for us */
+# In this example, we inherit the attributes of the "button" style and then
+# override the font and background color when prelit to create a new
+# "main_button" style.
 
-  gtk_selection_data_set (selection_data, GDK_SELECTION_TYPE_STRING,
-                         8, timestr, strlen(timestr));
+style "main_button" = "button"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
+  bg[PRELIGHT] = { 0.75, 0, 0 }
 }
 
-int
-main (int argc, char *argv[])
+style "toggle_button" = "button"
 {
-  GtkWidget *window;
-
-  GtkWidget *selection_button;
-
-  static int have_selection = FALSE;
+  fg[NORMAL] = { 1.0, 0, 0 }
+  fg[ACTIVE] = { 1.0, 0, 0 }
   
-  gtk_init (&amp;argc, &amp;argv);
-
-  /* Create the toplevel window */
-
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  gtk_window_set_title (GTK_WINDOW (window), "Event Box");
-  gtk_container_border_width (GTK_CONTAINER (window), 10);
+  # This sets the background pixmap of the toggle_button to that of it's
+  # parent widget (as defined in the application).
+  bg_pixmap[NORMAL] = "<parent>"
+}
 
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+style "text"
+{
+  bg_pixmap[NORMAL] = "marble.xpm"
+  fg[NORMAL] = { 1.0, 1.0, 1.0 }
+}
 
-  /* Create a toggle button to act as the selection */
+style "ruler"
+{
+  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+}
 
-  selection_button = gtk_toggle_button_new_with_label ("Claim Selection");
-  gtk_container_add (GTK_CONTAINER (window), selection_button);
-  gtk_widget_show (selection_button);
+# pixmap_path "~/.pixmaps"
 
-  gtk_signal_connect (GTK_OBJECT(selection_button), "toggled",
-                     GTK_SIGNAL_FUNC (selection_toggled), &amp;have_selection);
-  gtk_signal_connect (GTK_OBJECT(selection_button), "selection_clear_event",
-                     GTK_SIGNAL_FUNC (selection_clear), &amp;have_selection);
+# These set the widget types to use the styles defined above.
+# The widget types are listed in the class hierarchy, but could probably be
+# just listed in this document for the users reference.
 
-  gtk_selection_add_handler (selection_button, GDK_SELECTION_PRIMARY,
-                            GDK_SELECTION_TYPE_STRING,
-                            selection_handle, NULL);
+widget_class "GtkWindow" style "window"
+widget_class "GtkDialog" style "window"
+widget_class "GtkFileSelection" style "window"
+widget_class "*Gtk*Scale" style "scale"
+widget_class "*GtkCheckButton*" style "toggle_button"
+widget_class "*GtkRadioButton*" style "toggle_button"
+widget_class "*GtkButton*" style "button"
+widget_class "*Ruler" style "ruler"
+widget_class "*GtkText" style "text"
 
-  gtk_widget_show (selection_button);
-  gtk_widget_show (window);
-  
-  gtk_main ();
-  
-  return 0;
-}
-/* example-end */
+# This sets all the buttons that are children of the "main window" to
+# the main_buton style.  These must be documented to be taken advantage of.
+widget "main window.*GtkButton*" style "main_button"
 </verb></tscreen>
 
-
 <!-- ***************************************************************** -->
-<sect>glib<label id="sec_glib">
+<sect>Writing Your Own Widgets 
 <!-- ***************************************************************** -->
+
+<!-- ----------------------------------------------------------------- -->
+<sect1> Overview
 <p>
-glib provides many useful functions and definitions available for use
-when creating GDK and GTK applications. I will list them all here with
-a brief explanation. Many are duplicates of standard libc functions so
-I won't go into detail on those. This is mostly to be used as a reference,
-so you know what is available for use.
+Although the GTK distribution comes with many types of widgets that
+should cover most basic needs, there may come a time when you need to
+create your own new widget type. Since GTK uses widget inheretence
+extensively, and there is already a widget that is close to what you want,
+it is often possible to make a useful new widget type in
+just a few lines of code. But before starting work on a new widget, check
+around first to make sure that someone has not already written
+it. This will prevent duplication of effort and keep the number of
+GTK widgets out there to a minimum, which will help keep both the code
+and the interface of different applications consistent. As a flip side
+to this, once you finish your widget, announce it to the world so
+other people can benefit. The best place to do this is probably the
+<tt>gtk-list</tt>.
+
+Complete sources for the example widgets are available at the place you 
+got this tutorial, or from:
+
+<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
+name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Definitions
+<sect1> The Anatomy Of A Widget
 <p>
-Definitions for the extremes of many of the standard types are:
+In order to create a new widget, it is important to have an
+understanding of how GTK objects work. This section is just meant as a
+brief overview. See the reference documentation for the details. 
+
+GTK widgets are implemented in an object oriented fashion. However,
+they are implemented in standard C. This greatly improves portability
+and stability over using current generation C++ compilers; however,
+it does mean that the widget writer has to pay attention to some of
+the implementation details. The information common to all instances of
+one class of widgets (e.g., to all Button widgets) is stored in the 
+<em>class structure</em>. There is only one copy of this in
+which is stored information about the class's signals
+(which act like virtual functions in C). To support inheritance, the
+first field in the class structure must be a copy of the parent's
+class structure. The declaration of the class structure of GtkButtton
+looks like:
 
 <tscreen><verb>
-G_MINFLOAT
-G_MAXFLOAT
-G_MINDOUBLE
-G_MAXDOUBLE
-G_MINSHORT
-G_MAXSHORT
-G_MININT
-G_MAXINT
-G_MINLONG
-G_MAXLONG
+struct _GtkButtonClass
+{
+  GtkContainerClass parent_class;
+
+  void (* pressed)  (GtkButton *button);
+  void (* released) (GtkButton *button);
+  void (* clicked)  (GtkButton *button);
+  void (* enter)    (GtkButton *button);
+  void (* leave)    (GtkButton *button);
+};
 </verb></tscreen>
 
-Also, the following typedefs. The ones left unspecified are dynamically set
-depending on the architecture. Remember to avoid counting on the size of a
-pointer if you want to be portable! Eg, a pointer on an Alpha is 8 bytes, but 4
-on Intel.
+When a button is treated as a container (for instance, when it is
+resized), its class structure can be cast to GtkContainerClass, and
+the relevant fields used to handle the signals.
+
+There is also a structure for each widget that is created on a
+per-instance basis. This structure has fields to store information that
+is different for each instance of the widget. We'll call this
+structure the <em>object structure</em>. For the Button class, it looks
+like:
 
 <tscreen><verb>
-char   gchar;
-short  gshort;
-long   glong;
-int    gint;
-char   gboolean;
+struct _GtkButton
+{
+  GtkContainer container;
 
-unsigned char   guchar;
-unsigned short  gushort;
-unsigned long   gulong;
-unsigned int    guint;
+  GtkWidget *child;
 
-float   gfloat;
-double  gdouble;
-long double gldouble;
+  guint in_button : 1;
+  guint button_down : 1;
+};
+</verb></tscreen>
 
-void* gpointer;
+Note that, similar to the class structure, the first field is the
+object structure of the parent class, so that this structure can be
+cast to the parent class's object structure as needed.
 
-gint8
-guint8
-gint16
-guint16
-gint32
-guint32
-</verb></tscreen>
+<!-- ----------------------------------------------------------------- -->
+<sect1> Creating a Composite widget
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Doubly Linked Lists
+<sect2> Introduction
 <p>
-The following functions are used to create, manage, and destroy doubly
-linked lists.  I assume you know what linked lists are, as it is beyond the scope
-of this document to explain them.  Of course, it's not required that you
-know these for general use of GTK, but they are nice to know.
-
-<tscreen><verb>
-GList *g_list_alloc( void );
+One type of widget that you may be interested in creating is a
+widget that is merely an aggregate of other GTK widgets. This type of
+widget does nothing that couldn't be done without creating new
+widgets, but provides a convenient way of packaging user interface
+elements for reuse. The FileSelection and ColorSelection widgets in
+the standard distribution are examples of this type of widget.
 
-void g_list_free( GList *list );
+The example widget that we'll create in this section is the Tictactoe
+widget, a 3x3 array of toggle buttons which triggers a signal when all
+three buttons in a row, column, or on one of the diagonals are
+depressed. 
 
-void g_list_free_1( GList *list );
+<!-- ----------------------------------------------------------------- -->
+<sect2> Choosing a parent class
+<p>
+The parent class for a composite widget is typically the container
+class that holds all of the elements of the composite widget. For
+example, the parent class of the FileSelection widget is the
+Dialog class. Since our buttons will be arranged in a table, it
+might seem natural to make our parent class the GtkTable
+class. Unfortunately, this turns out not to work. The creation of a
+widget is divided among two functions - a <tt/WIDGETNAME_new()/
+function that the user calls, and a <tt/WIDGETNAME_init()/ function
+which does the basic work of initializing the widget which is
+independent of the arguments passed to the <tt/_new()/
+function. Descendent widgets only call the <tt/_init/ function of
+their parent widget. But this division of labor doesn't work well for
+tables, which when created, need to know the number of rows and
+columns in the table. Unless we want to duplicate most of the
+functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
+best avoid deriving it from GtkTable. For that reason, we derive it
+from GtkVBox instead, and stick our table inside the VBox.
 
-GList *g_list_append( GList     *list,
-                      gpointer   data );
-                          
-GList *g_list_prepend( GList    *list,
-                       gpointer  data );
-                       
-GList *g_list_insert( GList    *list,
-                      gpointer  data,
-                           gint      position );
+<!-- ----------------------------------------------------------------- -->
+<sect2> The header file
+<p>
+Each widget class has a header file which declares the object and
+class structures for that widget, along with public functions. 
+A couple of features are worth pointing out. To prevent duplicate
+definitions, we wrap the entire header file in:
 
-GList *g_list_remove( GList    *list,
-                      gpointer  data );
-                          
-GList *g_list_remove_link( GList *list,
-                           GList *link );
+<tscreen><verb>
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
+.
+.
+.
+#endif /* __TICTACTOE_H__ */
+</verb></tscreen>
 
-GList *g_list_reverse( GList *list );
+And to keep C++ programs that include the header file happy, in:
 
-GList *g_list_nth( GList *list,
-                   gint   n );
-                          
-GList *g_list_find( GList    *list,
-                    gpointer  data );
+<tscreen><verb>
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+.
+.
+.
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
+</verb></tscreen>
 
-GList *g_list_last( GList *list );
+Along with the functions and structures, we declare three standard
+macros in our header file, <tt/TICTACTOE(obj)/,
+<tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
+pointer into a pointer to the object or class structure, and check
+if an object is a Tictactoe widget respectively.
 
-GList *g_list_first( GList *list );
+Here is the complete header file:
 
-gint g_list_length( GList *list );
+<tscreen><verb>
+/* tictactoe.h */
 
-void g_list_foreach( GList    *list,
-                     GFunc     func,
-                     gpointer  user_data );
-</verb></tscreen>                                            
+#ifndef __TICTACTOE_H__
+#define __TICTACTOE_H__
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Singly Linked Lists
-<p>
-Many of the above functions for singly linked lists are identical to the
-above. Here is a complete list:
-<tscreen><verb>
-GSList *g_slist_alloc( void );
+#include <gdk/gdk.h>
+#include <gtk/gtkvbox.h>
 
-void g_slist_free( GSList *list );
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
-void g_slist_free_1( GSList *list );
+#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
+#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
+#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
 
-GSList *g_slist_append( GSList   *list,
-                        gpointer  data );
-               
-GSList *g_slist_prepend( GSList   *list,
-                         gpointer  data );
-                            
-GSList *g_slist_insert( GSList   *list,
-                        gpointer  data,
-                           gint      position );
-                            
-GSList *g_slist_remove( GSList   *list,
-                        gpointer  data );
-                            
-GSList *g_slist_remove_link( GSList *list,
-                             GSList *link );
-                            
-GSList *g_slist_reverse( GSList *list );
 
-GSList *g_slist_nth( GSList *list,
-                     gint    n );
-                            
-GSList *g_slist_find( GSList   *list,
-                      gpointer  data );
-                            
-GSList *g_slist_last( GSList *list );
+typedef struct _Tictactoe       Tictactoe;
+typedef struct _TictactoeClass  TictactoeClass;
 
-gint g_slist_length( GSList *list );
+struct _Tictactoe
+{
+  GtkVBox vbox;
+  
+  GtkWidget *buttons[3][3];
+};
 
-void g_slist_foreach( GSList   *list,
-                      GFunc     func,
-                           gpointer  user_data );
-       
-</verb></tscreen>
+struct _TictactoeClass
+{
+  GtkVBoxClass parent_class;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Memory Management
-<p>
-<tscreen><verb>
-gpointer g_malloc( gulong size );
-</verb></tscreen>
+  void (* tictactoe) (Tictactoe *ttt);
+};
 
-This is a replacement for malloc(). You do not need to check the return
-vaule as it is done for you in this function.
+guint          tictactoe_get_type        (void);
+GtkWidget*     tictactoe_new             (void);
+void          tictactoe_clear           (Tictactoe *ttt);
 
-<tscreen><verb>
-gpointer g_malloc0( gulong size );
-</verb></tscreen>
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-Same as above, but zeroes the memory before returning a pointer to it.
+#endif /* __TICTACTOE_H__ */
 
-<tscreen><verb>
-gpointer g_realloc( gpointer mem,
-                    gulong   size );
 </verb></tscreen>
 
-Relocates "size" bytes of memory starting at "mem".  Obviously, the
-memory should have been previously allocated.
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <tt/_get_type()/ function.
+<p>
+We now continue on to the implementation of our widget. A core
+function for every widget is the function
+<tt/WIDGETNAME_get_type()/. This function, when first called, tells
+GTK about the widget class, and gets an ID that uniquely identifies
+the widget class. Upon subsequent calls, it just returns the ID.
 
 <tscreen><verb>
-void g_free( gpointer mem );
-</verb></tscreen>
+guint
+tictactoe_get_type ()
+{
+  static guint ttt_type = 0;
 
-Frees memory. Easy one.
+  if (!ttt_type)
+    {
+      GtkTypeInfo ttt_info =
+      {
+       "Tictactoe",
+       sizeof (Tictactoe),
+       sizeof (TictactoeClass),
+       (GtkClassInitFunc) tictactoe_class_init,
+       (GtkObjectInitFunc) tictactoe_init,
+       (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL
+      };
 
-<tscreen><verb>
-void g_mem_profile( void );
+      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
+    }
+
+  return ttt_type;
+}
 </verb></tscreen>
 
-Dumps a profile of used memory, but requries that you add #define
-MEM_PROFILE to the top of glib/gmem.c and re-make and make install.
+The GtkTypeInfo structure has the following definition:
 
 <tscreen><verb>
-void g_mem_check( gpointer mem );
+struct _GtkTypeInfo
+{
+  gchar *type_name;
+  guint object_size;
+  guint class_size;
+  GtkClassInitFunc class_init_func;
+  GtkObjectInitFunc object_init_func;
+  GtkArgSetFunc arg_set_func;
+  GtkArgGetFunc arg_get_func;
+};
 </verb></tscreen>
 
-Checks that a memory location is valid.  Requires you add #define
-MEM_CHECK to the top of gmem.c and re-make and make install.
+The fields of this structure are pretty self-explanatory. We'll ignore
+the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important, 
+but as yet largely
+unimplemented, role in allowing widget options to be conveniently set
+from interpreted languages. Once GTK has a correctly filled in copy of
+this structure, it knows how to create objects of a particular widget
+type. 
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>Timers
+<sect2> The <tt/_class_init()/ function
 <p>
-Timer functions..
+The <tt/WIDGETNAME_class_init()/ function initializes the fields of
+the widget's class structure, and sets up any signals for the
+class. For our Tictactoe widget it looks like:
 
 <tscreen><verb>
-GTimer *g_timer_new( void );
 
-void g_timer_destroy( GTimer *timer );
+enum {
+  TICTACTOE_SIGNAL,
+  LAST_SIGNAL
+};
 
-void g_timer_start( GTimer  *timer );
+static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
 
-void g_timer_stop( GTimer  *timer );
+static void
+tictactoe_class_init (TictactoeClass *class)
+{
+  GtkObjectClass *object_class;
 
-void g_timer_reset( GTimer  *timer );
+  object_class = (GtkObjectClass*) class;
+  
+  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
+                                        GTK_RUN_FIRST,
+                                        object_class->type,
+                                        GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
+                                        gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
 
-gdouble g_timer_elapsed( GTimer *timer,
-                         gulong *microseconds );
-</verb></tscreen>                       
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>String Handling
-<p>
-A whole mess of string handling functions. They all look very interesting, and
-probably better for many purposes than the standard C string functions, but
-require documentation.
+  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
 
-<tscreen><verb>
-GString *g_string_new( gchar *init );
+  class->tictactoe = NULL;
+}
+</verb></tscreen>
 
-void g_string_free( GString *string,
-                    gint     free_segment );
-                            
-GString *g_string_assign( GString *lval,
-                          gchar   *rval );
-                            
-GString *g_string_truncate( GString *string,
-                            gint     len );
-                            
-GString *g_string_append( GString *string,
-                          gchar   *val );
-                           
-GString *g_string_append_c( GString *string,
-                            gchar    c );
-       
-GString *g_string_prepend( GString *string,
-                           gchar   *val );
-                            
-GString *g_string_prepend_c( GString *string,
-                             gchar    c );
-       
-void g_string_sprintf( GString *string,
-                       gchar   *fmt,
-                       ...);
-       
-void g_string_sprintfa ( GString *string,
-                         gchar   *fmt,
-                         ... );
-</verb></tscreen>                                                        
+Our widget has just one signal, the <tt/tictactoe/ signal that is
+invoked when a row, column, or diagonal is completely filled in. Not
+every composite widget needs signals, so if you are reading this for
+the first time, you may want to skip to the next section now, as
+things are going to get a bit complicated.
+
+The function:
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Utility and Error Functions
-<p>
 <tscreen><verb>
-gchar *g_strdup( const gchar *str );
+gint gtk_signal_new( const gchar         *name,
+                     GtkSignalRunType     run_type,
+                     GtkType              object_type,
+                     gint                 function_offset,
+                     GtkSignalMarshaller  marshaller,
+                     GtkType              return_val,
+                     guint                nparams,
+                     ...);
 </verb></tscreen>
 
-Replacement strdup function.  Copies the original strings contents to
-newly allocated memory, and returns a pointer to it.
+Creates a new signal. The parameters are:
 
-<tscreen><verb>
-gchar *g_strerror( gint errnum );
-</verb></tscreen>
+<itemize>
+<item> <tt/name/: The name of the signal.
+<item> <tt/run_type/: Whether the default handler runs before or after
+user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
+although there are other possibilities.
+<item> <tt/object_type/: The ID of the object that this signal applies
+to. (It will also apply to that objects descendents)
+<item> <tt/function_offset/: The offset within the class structure of
+a pointer to the default handler.
+<item> <tt/marshaller/: A function that is used to invoke the signal
+handler. For signal handlers that have no arguments other than the
+object that emitted the signal and user data, we can use the
+pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
+<item> <tt/return_val/: The type of the return val.
+<item> <tt/nparams/: The number of parameters of the signal handler
+(other than the two default ones mentioned above)
+<item> <tt/.../: The types of the parameters.
+</itemize>
 
-I recommend using this for all error messages.  It's much nicer, and more
-portable than perror() or others.  The output is usually of the form:
+When specifying types, the <tt/GtkType/ enumeration is used:
 
 <tscreen><verb>
-program name:function that failed:file or further description:strerror
-</verb></tscreen>
+typedef enum
+{
+  GTK_TYPE_INVALID,
+  GTK_TYPE_NONE,
+  GTK_TYPE_CHAR,
+  GTK_TYPE_BOOL,
+  GTK_TYPE_INT,
+  GTK_TYPE_UINT,
+  GTK_TYPE_LONG,
+  GTK_TYPE_ULONG,
+  GTK_TYPE_FLOAT,
+  GTK_TYPE_DOUBLE,
+  GTK_TYPE_STRING,
+  GTK_TYPE_ENUM,
+  GTK_TYPE_FLAGS,
+  GTK_TYPE_BOXED,
+  GTK_TYPE_FOREIGN,
+  GTK_TYPE_CALLBACK,
+  GTK_TYPE_ARGS,
 
-Here's an example of one such call used in our hello_world program:
+  GTK_TYPE_POINTER,
 
-<tscreen><verb>
-g_print("hello_world:open:%s:%s\n", filename, g_strerror(errno));
-</verb></tscreen>
+  /* it'd be great if the next two could be removed eventually */
+  GTK_TYPE_SIGNAL,
+  GTK_TYPE_C_CALLBACK,
 
-<tscreen><verb>
-void g_error( gchar *format, ... );
+  GTK_TYPE_OBJECT
+
+} GtkFundamentalType;
 </verb></tscreen>
 
-Prints an error message. The format is just like printf, but it
-prepends "** ERROR **: " to your message, and exits the program.  
-Use only for fatal errors.
+<tt/gtk_signal_new()/ returns a unique integer identifier for the
+signal, that we store in the <tt/tictactoe_signals/ array, which we
+index using an enumeration. (Conventionally, the enumeration elements
+are the signal name, uppercased, but here there would be a conflict
+with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
+instead.
+
+After creating our signals, we need to tell GTK to associate our
+signals with the Tictactoe class. We do that by calling
+<tt/gtk_object_class_add_signals()/. We then set the pointer which
+points to the default handler for the ``tictactoe'' signal to NULL,
+indicating that there is no default action.
+
+<!-- ----------------------------------------------------------------- -->
+<sect2> The <tt/_init()/ function.
+<p>
+Each widget class also needs a function to initialize the object
+structure. Usually, this function has the fairly limited role of
+setting the fields of the structure to default values. For composite
+widgets, however, this function also creates the component widgets.
 
 <tscreen><verb>
-void g_warning( gchar *format, ... );
+static void
+tictactoe_init (Tictactoe *ttt)
+{
+  GtkWidget *table;
+  gint i,j;
+  
+  table = gtk_table_new (3, 3, TRUE);
+  gtk_container_add (GTK_CONTAINER(ttt), table);
+  gtk_widget_show (table);
+
+  for (i=0;i<3; i++)
+    for (j=0;j<3; j++)
+      {
+       ttt->buttons[i][j] = gtk_toggle_button_new ();
+       gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
+                                  i, i+1, j, j+1);
+       gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
+                           GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
+       gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
+       gtk_widget_show (ttt->buttons[i][j]);
+      }
+}
 </verb></tscreen>
 
-Same as above, but prepends "** WARNING **: ", and does not exit the
-program.
-
-<tscreen><verb>
-void g_message( gchar *format, ... );
-</verb></tscreen>
+<!-- ----------------------------------------------------------------- -->
+<sect2> And the rest...
+<p>
+There is one more function that every widget (except for base widget
+types like GtkBin that cannot be instantiated) needs to have - the
+function that the user calls to create an object of that type. This is
+conventionally called <tt/WIDGETNAME_new()/. In some
+widgets, though not for the Tictactoe widgets, this function takes
+arguments, and does some setup based on the arguments. The other two
+functions are specific to the Tictactoe widget. 
 
-Prints "message: " prepended to the string you pass in.
+<tt/tictactoe_clear()/ is a public function that resets all the
+buttons in the widget to the up position. Note the use of
+<tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
+button toggles from being triggered unnecessarily.
 
-<tscreen><verb>
-void g_print( gchar *format, ... );
-</verb></tscreen>
+<tt/tictactoe_toggle()/ is the signal handler that is invoked when the
+user clicks on a button. It checks to see if there are any winning
+combinations that involve the toggled button, and if so, emits
+the "tictactoe" signal.
 
-Replacement for printf().
+<tscreen><verb>  
+GtkWidget*
+tictactoe_new ()
+{
+  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+}
 
-And our last function:
+void          
+tictactoe_clear (Tictactoe *ttt)
+{
+  int i,j;
 
-<tscreen><verb>
-gchar *g_strsignal( gint signum );
-</verb></tscreen>
+  for (i=0;i<3;i++)
+    for (j=0;j<3;j++)
+      {
+       gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
+                                    FALSE);
+       gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
+      }
+}
 
-Prints out the name of the Unix system signal given the signal number.
-Useful in generic signal handling functions.
+static void
+tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+{
+  int i,k;
 
-All of the above are more or less just stolen from glib.h.  If anyone cares
-to document any function, just send me an email!
+  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 1, 2 }, { 0, 1, 2 } };
+  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
+                            { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
+                            { 0, 1, 2 }, { 2, 1, 0 } };
 
-<!-- ***************************************************************** -->
-<sect>GTK's rc Files
-<!-- ***************************************************************** -->
-<p>
-GTK has it's own way of dealing with application defaults, by using rc
-files. These can be used to set the colors of just about any widget, and
-can also be used to tile pixmaps onto the background of some widgets.  
+  int success, found;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Functions For rc Files 
-<p>
-When your application starts, you should include a call to:
+  for (k=0; k<8; k++)
+    {
+      success = TRUE;
+      found = FALSE;
 
-<tscreen><verb>
-void gtk_rc_parse( char *filename );
+      for (i=0;i<3;i++)
+       {
+         success = success &amp;&amp; 
+           GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
+         found = found ||
+           ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
+       }
+      
+      if (success &amp;&amp; found)
+       {
+         gtk_signal_emit (GTK_OBJECT (ttt), 
+                          tictactoe_signals[TICTACTOE_SIGNAL]);
+         break;
+       }
+    }
+}
 </verb></tscreen>
 
-Passing in the filename of your rc file.  This will cause GTK to parse this
-file, and use the style settings for the widget types defined there.
-
-If you wish to have a special set of widgets that can take on a different
-style from others, or any other logical division of widgets, use a call to:
+And finally, an example program using our Tictactoe widget:
 
 <tscreen><verb>
-void gtk_widget_set_name( GtkWidget *widget,
-                          gchar     *name );
-</verb></tscreen>
-
-Passing your newly created widget as the first argument, and the name
-you wish to give it as the second. This will allow you to change the
-attributes of this widget by name through the rc file.
+#include <gtk/gtk.h>
+#include "tictactoe.h"
 
-If we use a call something like this:
+/* Invoked when a row, column or diagonal is completed */
+void
+win (GtkWidget *widget, gpointer data)
+{
+  g_print ("Yay!\n");
+  tictactoe_clear (TICTACTOE (widget));
+}
 
-<tscreen><verb>
-button = gtk_button_new_with_label ("Special Button");
-gtk_widget_set_name (button, "special button");
-</verb></tscreen>
+int 
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *ttt;
+  
+  gtk_init (&amp;argc, &amp;argv);
 
-Then this button is given the name "special button" and may be addressed by
-name in the rc file as "special button.GtkButton".  [<--- Verify ME!]
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  
+  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
+  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
+  
+  gtk_container_border_width (GTK_CONTAINER (window), 10);
 
-The example rc file below, sets the properties of the main window, and lets
-all children of that main window inherit the style described by the "main
-button" style.  The code used in the application is:
+  /* Create a new Tictactoe widget */
+  ttt = tictactoe_new ();
+  gtk_container_add (GTK_CONTAINER (window), ttt);
+  gtk_widget_show (ttt);
 
-<tscreen><verb>
-window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-gtk_widget_set_name (window, "main window");
-</verb></tscreen>
+  /* And attach to its "tictactoe" signal */
+  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
+                     GTK_SIGNAL_FUNC (win), NULL);
 
-And then the style is defined in the rc file using:
+  gtk_widget_show (window);
+  
+  gtk_main ();
+  
+  return 0;
+}
 
-<tscreen><verb>
-widget "main window.*GtkButton*" style "main_button"
 </verb></tscreen>
 
-Which sets all the GtkButton widgets in the "main window" to the
-"main_buttons" style as defined in the rc file.
-
-As you can see, this is a fairly powerful and flexible system.  Use your
-imagination as to how best to take advantage of this.
+<!-- ----------------------------------------------------------------- -->
+<sect1> Creating a widget from scratch.
 
 <!-- ----------------------------------------------------------------- -->
-<sect1>GTK's rc File Format
+<sect2> Introduction
 <p>
-The format of the GTK file is illustrated in the example below. This is
-the testgtkrc file from the GTK distribution, but I've added a
-few comments and things. You may wish to include this explanation
-your application to allow the user to fine tune his application.
-
-There are several directives to change the attributes of a widget.
-
-<itemize>
-<item>fg - Sets the foreground color of a widget.
-<item>bg - Sets the background color of a widget.
-<item>bg_pixmap - Sets the background of a widget to a tiled pixmap.
-<item>font - Sets the font to be used with the given widget.
-</itemize>
+In this section, we'll learn more about how widgets display themselves
+on the screen and interact with events. As an example of this, we'll
+create an analog dial widget with a pointer that the user can drag to
+set the value.
 
-In addition to this, there are several states a widget can be in, and you
-can set different colors, pixmaps and fonts for each state. These states are:
+<!-- ----------------------------------------------------------------- -->
+<sect2> Displaying a widget on the screen
+<p>
+There are several steps that are involved in displaying on the screen.
+After the widget is created with a call to <tt/WIDGETNAME_new()/,
+several more functions are needed:
 
 <itemize>
-<item>NORMAL - The normal state of a widget, without the mouse over top of
-it, and not being pressed etc.
-<item>PRELIGHT - When the mouse is over top of the widget, colors defined
-using this state will be in effect.
-<item>ACTIVE - When the widget is pressed or clicked it will be active, and
-the attributes assigned by this tag will be in effect.
-<item>INSENSITIVE - When a widget is set insensitive, and cannot be
-activated, it will take these attributes.
-<item>SELECTED - When an object is selected, it takes these attributes.
+<item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
+window for the widget if it has one.
+<item> <tt/WIDGETNAME_map()/ is invoked after the user calls
+<tt/gtk_widget_show()/. It is responsible for making sure the widget
+is actually drawn on the screen (<em/mapped/). For a container class,
+it must also make calls to <tt/map()/> functions of any child widgets.
+<item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
+is called for the widget or one of its ancestors. It makes the actual
+calls to the drawing functions to draw the widget on the screen. For
+container widgets, this function must make calls to
+<tt/gtk_widget_draw()/ for its child widgets.
+<item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
+widget. It makes the necessary calls to the drawing functions to draw
+the exposed portion on the screen. For container widgets, this
+function must generate expose events for its child widgets which don't
+have their own windows. (If they have their own windows, then X will
+generate the necessary expose events)
 </itemize>
 
-When using the "fg" and "bg" keywords to set the colors of widgets, the
-format is:
+You might notice that the last two functions are quite similar - each
+is responsible for drawing the widget on the screen. In fact many
+types of widgets don't really care about the difference between the
+two. The default <tt/draw()/ function in the widget class simply
+generates a synthetic expose event for the redrawn area. However, some
+types of widgets can save work by distinguishing between the two
+functions. For instance, if a widget has multiple X windows, then
+since expose events identify the exposed window, it can redraw only
+the affected window, which is not possible for calls to <tt/draw()/.
 
-<tscreen><verb>
-fg[<STATE>] = { Red, Green, Blue }
-</verb></tscreen>
+Container widgets, even if they don't care about the difference for
+themselves, can't simply use the default <tt/draw()/ function because
+their child widgets might care about the difference. However,
+it would be wasteful to duplicate the drawing code between the two
+functions. The convention is that such widgets have a function called
+<tt/WIDGETNAME_paint()/ that does the actual work of drawing the
+widget, that is then called by the <tt/draw()/ and <tt/expose()/
+functions.
 
-Where STATE is one of the above states (PRELIGHT, ACTIVE etc), and the Red,
-Green and Blue are values in the range of 0 - 1.0,  { 1.0, 1.0, 1.0 } being
-white. They must be in float form, or they will register as 0, so a straight 
-"1" will not work, it must be "1.0".  A straight "0" is fine because it 
-doesn't matter if it's not recognized.  Unrecognized values are set to 0.
+In our example approach, since the dial widget is not a container
+widget, and only has a single window, we can take the simplest
+approach and use the default <tt/draw()/ function and only implement
+an <tt/expose()/ function.
 
-bg_pixmap is very similar to the above, except the colors are replaced by a
-filename.
+<!-- ----------------------------------------------------------------- -->
+<sect2> The origins of the Dial Widget
+<p>
+Just as all land animals are just variants on the first amphibian that
+crawled up out of the mud, Gtk widgets tend to start off as variants
+of some other, previously written widget.  Thus, although this section
+is entilted ``Creating a Widget from Scratch'', the Dial widget really
+began with the source code for the Range widget. This was picked as a
+starting point because it would be nice if our Dial had the same
+interface as the Scale widgets which are just specialized descendents
+of the Range widget. So, though the source code is presented below in
+finished form, it should not be implied that it was written, <em>deus
+ex machina</em> in this fashion. Also, if you aren't yet familiar with
+how scale widgets work from the application writer's point of view, it
+would be a good idea to look them over before continuing.
 
-pixmap_path is a list of paths seperated by ":"'s.  These paths will be
-searched for any pixmap you specify.
+<!-- ----------------------------------------------------------------- -->
+<sect2> The Basics
+<p>
+Quite a bit of our widget should look pretty familiar from the
+Tictactoe widget. First, we have a header file:
 
-The font directive is simply:
 <tscreen><verb>
-font = "<font name>"
-</verb></tscreen>
-
-Where the only hard part is figuring out the font string. Using xfontsel or
-similar utility should help.
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
 
-The "widget_class" sets the style of a class of widgets. These classes are
-listed in the widget overview on the class hierarchy.
+#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__
 
-The "widget" directive sets a specificaly named set of widgets to a
-given style, overriding any style set for the given widget class.
-These widgets are registered inside the application using the
-gtk_widget_set_name() call. This allows you to specify the attributes of a
-widget on a per widget basis, rather than setting the attributes of an
-entire widget class. I urge you to document any of these special widgets so
-users may customize them.
+#include <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
 
-When the keyword <tt>parent</> is used as an attribute, the widget will take on
-the attributes of it's parent in the application.
 
-When defining a style, you may assign the attributes of a previously defined
-style to this new one.
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
 
-<tscreen><verb>
-style "main_button" = "button"
-{
-  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
-  bg[PRELIGHT] = { 0.75, 0, 0 }
-}
-</verb></tscreen>
 
-This example takes the "button" style, and creates a new "main_button" style
-simply by changing the font and prelight background color of the "button"
-style.
+#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
 
-Of course, many of these attributes don't apply to all widgets. It's a
-simple matter of common sense really. Anything that could apply, should.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1>Example rc file
-<p>
+typedef struct _GtkDial        GtkDial;
+typedef struct _GtkDialClass   GtkDialClass;
 
-<tscreen><verb>
-# pixmap_path "<dir 1>:<dir 2>:<dir 3>:..."
-#
-pixmap_path "/usr/include/X11R6/pixmaps:/home/imain/pixmaps"
-#
-# style <name> [= <name>]
-# {
-#   <option>
-# }
-#
-# widget <widget_set> style <style_name>
-# widget_class <widget_class_set> style <style_name>
+struct _GtkDial
+{
+  GtkWidget widget;
 
+  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+  guint policy : 2;
 
-# Here is a list of all the possible states.  Note that some do not apply to
-# certain widgets.
-#
-# NORMAL - The normal state of a widget, without the mouse over top of
-# it, and not being pressed etc.
-#
-# PRELIGHT - When the mouse is over top of the widget, colors defined
-# using this state will be in effect.
-#
-# ACTIVE - When the widget is pressed or clicked it will be active, and
-# the attributes assigned by this tag will be in effect.
-#
-# INSENSITIVE - When a widget is set insensitive, and cannot be
-# activated, it will take these attributes.
-#
-# SELECTED - When an object is selected, it takes these attributes.
-#
-# Given these states, we can set the attributes of the widgets in each of
-# these states using the following directives.
-#
-# fg - Sets the foreground color of a widget.
-# fg - Sets the background color of a widget.
-# bg_pixmap - Sets the background of a widget to a tiled pixmap.
-# font - Sets the font to be used with the given widget.
-#
+  /* Button currently pressed or 0 if none */
+  guint8 button;
 
-# This sets a style called "button".  The name is not really important, as
-# it is assigned to the actual widgets at the bottom of the file.
+  /* Dimensions of dial components */
+  gint radius;
+  gint pointer_width;
 
-style "window"
-{
-  #This sets the padding around the window to the pixmap specified.
-  #bg_pixmap[<STATE>] = "<pixmap filename>"
-  bg_pixmap[NORMAL] = "warning.xpm"
-}
+  /* ID of update timer, or 0 if none */
+  guint32 timer;
 
-style "scale"
-{
-  #Sets the foreground color (font color) to red when in the "NORMAL"
-  #state.
-  
-  fg[NORMAL] = { 1.0, 0, 0 }
-  
-  #Sets the background pixmap of this widget to that of it's parent.
-  bg_pixmap[NORMAL] = "<parent>"
-}
+  /* Current angle */
+  gfloat angle;
 
-style "button"
-{
-  # This shows all the possible states for a button.  The only one that
-  # doesn't apply is the SELECTED state.
-  
-  fg[PRELIGHT] = { 0, 1.0, 1.0 }
-  bg[PRELIGHT] = { 0, 0, 1.0 }
-  bg[ACTIVE] = { 1.0, 0, 0 }
-  fg[ACTIVE] = { 0, 1.0, 0 }
-  bg[NORMAL] = { 1.0, 1.0, 0 }
-  fg[NORMAL] = { .99, 0, .99 }
-  bg[INSENSITIVE] = { 1.0, 1.0, 1.0 }
-  fg[INSENSITIVE] = { 1.0, 0, 1.0 }
-}
+  /* Old values from adjustment stored so we know when something changes */
+  gfloat old_value;
+  gfloat old_lower;
+  gfloat old_upper;
 
-# In this example, we inherit the attributes of the "button" style and then
-# override the font and background color when prelit to create a new
-# "main_button" style.
+  /* The adjustment object that stores the data for this dial */
+  GtkAdjustment *adjustment;
+};
 
-style "main_button" = "button"
+struct _GtkDialClass
 {
-  font = "-adobe-helvetica-medium-r-normal--*-100-*-*-*-*-*-*"
-  bg[PRELIGHT] = { 0.75, 0, 0 }
-}
+  GtkWidgetClass parent_class;
+};
 
-style "toggle_button" = "button"
-{
-  fg[NORMAL] = { 1.0, 0, 0 }
-  fg[ACTIVE] = { 1.0, 0, 0 }
-  
-  # This sets the background pixmap of the toggle_button to that of it's
-  # parent widget (as defined in the application).
-  bg_pixmap[NORMAL] = "<parent>"
-}
 
-style "text"
-{
-  bg_pixmap[NORMAL] = "marble.xpm"
-  fg[NORMAL] = { 1.0, 1.0, 1.0 }
-}
+GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
+guint          gtk_dial_get_type               (void);
+GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
+void           gtk_dial_set_update_policy      (GtkDial      *dial,
+                                               GtkUpdateType  policy);
 
-style "ruler"
-{
-  font = "-adobe-helvetica-medium-r-normal--*-80-*-*-*-*-*-*"
+void           gtk_dial_set_adjustment         (GtkDial      *dial,
+                                               GtkAdjustment *adjustment);
+#ifdef __cplusplus
 }
+#endif /* __cplusplus */
 
-# pixmap_path "~/.pixmaps"
 
-# These set the widget types to use the styles defined above.
-# The widget types are listed in the class hierarchy, but could probably be
-# just listed in this document for the users reference.
+#endif /* __GTK_DIAL_H__ */
+</verb></tscreen>
 
-widget_class "GtkWindow" style "window"
-widget_class "GtkDialog" style "window"
-widget_class "GtkFileSelection" style "window"
-widget_class "*Gtk*Scale" style "scale"
-widget_class "*GtkCheckButton*" style "toggle_button"
-widget_class "*GtkRadioButton*" style "toggle_button"
-widget_class "*GtkButton*" style "button"
-widget_class "*Ruler" style "ruler"
-widget_class "*GtkText" style "text"
+Since there is quite a bit more going on in this widget, than the last
+one, we have more fields in the data structure, but otherwise things
+are pretty similar.
 
-# This sets all the buttons that are children of the "main window" to
-# the main_buton style.  These must be documented to be taken advantage of.
-widget "main window.*GtkButton*" style "main_button"
-</verb></tscreen>
+Next, after including header files, and declaring a few constants,
+we have some functions to provide information about the widget
+and initialize it:
 
-<!-- ***************************************************************** -->
-<sect>Writing Your Own Widgets 
-<!-- ***************************************************************** -->
+<tscreen><verb>
+#include <math.h>
+#include <stdio.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Overview
-<p>
-Although the GTK distribution comes with many types of widgets that
-should cover most basic needs, there may come a time when you need to
-create your own new widget type. Since GTK uses widget inheretence
-extensively, and there is already a widget that is close to what you want,
-it is often possible to make a useful new widget type in
-just a few lines of code. But before starting work on a new widget, check
-around first to make sure that someone has not already written
-it. This will prevent duplication of effort and keep the number of
-GTK widgets out there to a minimum, which will help keep both the code
-and the interface of different applications consistent. As a flip side
-to this, once you finish your widget, announce it to the world so
-other people can benefit. The best place to do this is probably the
-<tt>gtk-list</tt>.
+#include "gtkdial.h"
 
-Complete sources for the example widgets are available at the place you 
-got this tutorial, or from:
+#define SCROLL_DELAY_LENGTH  300
+#define DIAL_DEFAULT_SIZE 100
 
-<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
-name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+/* Forward declararations */
 
+[ omitted to save space ]
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> The Anatomy Of A Widget
-<p>
-In order to create a new widget, it is important to have an
-understanding of how GTK objects work. This section is just meant as a
-brief overview. See the reference documentation for the details. 
+/* Local data */
 
-GTK widgets are implemented in an object oriented fashion. However,
-they are implemented in standard C. This greatly improves portability
-and stability over using current generation C++ compilers; however,
-it does mean that the widget writer has to pay attention to some of
-the implementation details. The information common to all instances of
-one class of widgets (e.g., to all Button widgets) is stored in the 
-<em>class structure</em>. There is only one copy of this in
-which is stored information about the class's signals
-(which act like virtual functions in C). To support inheritance, the
-first field in the class structure must be a copy of the parent's
-class structure. The declaration of the class structure of GtkButtton
-looks like:
+static GtkWidgetClass *parent_class = NULL;
 
-<tscreen><verb>
-struct _GtkButtonClass
+guint
+gtk_dial_get_type ()
 {
-  GtkContainerClass parent_class;
+  static guint dial_type = 0;
 
-  void (* pressed)  (GtkButton *button);
-  void (* released) (GtkButton *button);
-  void (* clicked)  (GtkButton *button);
-  void (* enter)    (GtkButton *button);
-  void (* leave)    (GtkButton *button);
-};
-</verb></tscreen>
+  if (!dial_type)
+    {
+      GtkTypeInfo dial_info =
+      {
+       "GtkDial",
+       sizeof (GtkDial),
+       sizeof (GtkDialClass),
+       (GtkClassInitFunc) gtk_dial_class_init,
+       (GtkObjectInitFunc) gtk_dial_init,
+       (GtkArgSetFunc) NULL,
+        (GtkArgGetFunc) NULL,
+      };
 
-When a button is treated as a container (for instance, when it is
-resized), its class structure can be cast to GtkContainerClass, and
-the relevant fields used to handle the signals.
+      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+    }
 
-There is also a structure for each widget that is created on a
-per-instance basis. This structure has fields to store information that
-is different for each instance of the widget. We'll call this
-structure the <em>object structure</em>. For the Button class, it looks
-like:
+  return dial_type;
+}
 
-<tscreen><verb>
-struct _GtkButton
+static void
+gtk_dial_class_init (GtkDialClass *class)
 {
-  GtkContainer container;
-
-  GtkWidget *child;
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
 
-  guint in_button : 1;
-  guint button_down : 1;
-};
-</verb></tscreen>
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
 
-Note that, similar to the class structure, the first field is the
-object structure of the parent class, so that this structure can be
-cast to the parent class's object structure as needed.
+  parent_class = gtk_type_class (gtk_widget_get_type ());
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Creating a Composite widget
+  object_class->destroy = gtk_dial_destroy;
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Introduction
-<p>
-One type of widget that you may be interested in creating is a
-widget that is merely an aggregate of other GTK widgets. This type of
-widget does nothing that couldn't be done without creating new
-widgets, but provides a convenient way of packaging user interface
-elements for reuse. The FileSelection and ColorSelection widgets in
-the standard distribution are examples of this type of widget.
+  widget_class->realize = gtk_dial_realize;
+  widget_class->expose_event = gtk_dial_expose;
+  widget_class->size_request = gtk_dial_size_request;
+  widget_class->size_allocate = gtk_dial_size_allocate;
+  widget_class->button_press_event = gtk_dial_button_press;
+  widget_class->button_release_event = gtk_dial_button_release;
+  widget_class->motion_notify_event = gtk_dial_motion_notify;
+}
 
-The example widget that we'll create in this section is the Tictactoe
-widget, a 3x3 array of toggle buttons which triggers a signal when all
-three buttons in a row, column, or on one of the diagonals are
-depressed. 
+static void
+gtk_dial_init (GtkDial *dial)
+{
+  dial->button = 0;
+  dial->policy = GTK_UPDATE_CONTINUOUS;
+  dial->timer = 0;
+  dial->radius = 0;
+  dial->pointer_width = 0;
+  dial->angle = 0.0;
+  dial->old_value = 0.0;
+  dial->old_lower = 0.0;
+  dial->old_upper = 0.0;
+  dial->adjustment = NULL;
+}
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Choosing a parent class
-<p>
-The parent class for a composite widget is typically the container
-class that holds all of the elements of the composite widget. For
-example, the parent class of the FileSelection widget is the
-Dialog class. Since our buttons will be arranged in a table, it
-might seem natural to make our parent class the GtkTable
-class. Unfortunately, this turns out not to work. The creation of a
-widget is divided among two functions - a <tt/WIDGETNAME_new()/
-function that the user calls, and a <tt/WIDGETNAME_init()/ function
-which does the basic work of initializing the widget which is
-independent of the arguments passed to the <tt/_new()/
-function. Descendent widgets only call the <tt/_init/ function of
-their parent widget. But this division of labor doesn't work well for
-tables, which when created, need to know the number of rows and
-columns in the table. Unless we want to duplicate most of the
-functionality of <tt/gtk_table_new()/ in our Tictactoe widget, we had
-best avoid deriving it from GtkTable. For that reason, we derive it
-from GtkVBox instead, and stick our table inside the VBox.
+GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+  GtkDial *dial;
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The header file
-<p>
-Each widget class has a header file which declares the object and
-class structures for that widget, along with public functions. 
-A couple of features are worth pointing out. To prevent duplicate
-definitions, we wrap the entire header file in:
+  dial = gtk_type_new (gtk_dial_get_type ());
 
-<tscreen><verb>
-#ifndef __TICTACTOE_H__
-#define __TICTACTOE_H__
-.
-.
-.
-#endif /* __TICTACTOE_H__ */
-</verb></tscreen>
+  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
-And to keep C++ programs that include the header file happy, in:
+  gtk_dial_set_adjustment (dial, adjustment);
 
-<tscreen><verb>
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
-.
-.
-.
-#ifdef __cplusplus
+  return GTK_WIDGET (dial);
 }
-#endif /* __cplusplus */
-</verb></tscreen>
 
-Along with the functions and structures, we declare three standard
-macros in our header file, <tt/TICTACTOE(obj)/,
-<tt/TICTACTOE_CLASS(klass)/, and <tt/IS_TICTACTOE(obj)/, which cast a
-pointer into a pointer to the object or class structure, and check
-if an object is a Tictactoe widget respectively.
+static void
+gtk_dial_destroy (GtkObject *object)
+{
+  GtkDial *dial;
 
-Here is the complete header file:
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_DIAL (object));
 
-<tscreen><verb>
-/* tictactoe.h */
+  dial = GTK_DIAL (object);
 
-#ifndef __TICTACTOE_H__
-#define __TICTACTOE_H__
+  if (dial->adjustment)
+    gtk_object_unref (GTK_OBJECT (dial->adjustment));
 
-#include <gdk/gdk.h>
-#include <gtk/gtkvbox.h>
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+</verb></tscreen>
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+Note that this <tt/init()/ function does less than for the Tictactoe
+widget, since this is not a composite widget, and the <tt/new()/
+function does more, since it now has an argument. Also, note that when
+we store a pointer to the Adjustment object, we increment its
+reference count, (and correspondingly decrement when we no longer use
+it) so that GTK can keep track of when it can be safely destroyed.
 
-#define TICTACTOE(obj)          GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe)
-#define TICTACTOE_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass)
-#define IS_TICTACTOE(obj)       GTK_CHECK_TYPE (obj, tictactoe_get_type ())
+<p>
+Also, there are a few function to manipulate the widget's options:
 
+<tscreen><verb>
+GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
 
-typedef struct _Tictactoe       Tictactoe;
-typedef struct _TictactoeClass  TictactoeClass;
+  return dial->adjustment;
+}
 
-struct _Tictactoe
+void
+gtk_dial_set_update_policy (GtkDial      *dial,
+                            GtkUpdateType  policy)
 {
-  GtkVBox vbox;
-  
-  GtkWidget *buttons[3][3];
-};
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  dial->policy = policy;
+}
 
-struct _TictactoeClass
+void
+gtk_dial_set_adjustment (GtkDial      *dial,
+                         GtkAdjustment *adjustment)
 {
-  GtkVBoxClass parent_class;
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-  void (* tictactoe) (Tictactoe *ttt);
-};
+  if (dial->adjustment)
+    {
+      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+      gtk_object_unref (GTK_OBJECT (dial->adjustment));
+    }
 
-guint          tictactoe_get_type        (void);
-GtkWidget*     tictactoe_new             (void);
-void          tictactoe_clear           (Tictactoe *ttt);
+  dial->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (dial->adjustment));
 
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_changed,
+                     (gpointer) dial);
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+                     (gpointer) dial);
 
-#endif /* __TICTACTOE_H__ */
+  dial->old_value = adjustment->value;
+  dial->old_lower = adjustment->lower;
+  dial->old_upper = adjustment->upper;
 
+  gtk_dial_update (dial);
+}
 </verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The <tt/_get_type()/ function.
+<sect2> <tt/gtk_dial_realize()/
+
 <p>
-We now continue on to the implementation of our widget. A core
-function for every widget is the function
-<tt/WIDGETNAME_get_type()/. This function, when first called, tells
-GTK about the widget class, and gets an ID that uniquely identifies
-the widget class. Upon subsequent calls, it just returns the ID.
+Now we come to some new types of functions. First, we have a function
+that does the work of creating the X window. Notice that a mask is
+passed to the function <tt/gdk_window_new()/ which specifies which fields of
+the GdkWindowAttr structure actually have data in them (the remaining
+fields wll be given default values). Also worth noting is the way the
+event mask of the widget is created. We call
+<tt/gtk_widget_get_events()/ to retrieve the event mask that the user
+has specified for this widget (with <tt/gtk_widget_set_events()/, and
+add the events that we are interested in ourselves.
+
+<p>
+After creating the window, we set its style and background, and put a
+pointer to the widget in the user data field of the GdkWindow. This
+last step allows GTK to dispatch events for this window to the correct
+widget.
 
 <tscreen><verb>
-guint
-tictactoe_get_type ()
+static void
+gtk_dial_realize (GtkWidget *widget)
 {
-  static guint ttt_type = 0;
+  GtkDial *dial;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
 
-  if (!ttt_type)
-    {
-      GtkTypeInfo ttt_info =
-      {
-       "Tictactoe",
-       sizeof (Tictactoe),
-       sizeof (TictactoeClass),
-       (GtkClassInitFunc) tictactoe_class_init,
-       (GtkObjectInitFunc) tictactoe_init,
-       (GtkArgSetFunc) NULL,
-        (GtkArgGetFunc) NULL
-      };
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
 
-      ttt_type = gtk_type_unique (gtk_vbox_get_type (), &amp;ttt_info);
-    }
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  dial = GTK_DIAL (widget);
 
-  return ttt_type;
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
+
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
+
+  widget->style = gtk_style_attach (widget->style, widget->window);
+
+  gdk_window_set_user_data (widget->window, widget);
+
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
 }
 </verb></tscreen>
 
-The GtkTypeInfo structure has the following definition:
+<sect2> Size negotiation
+
+<p>
+Before the first time that the window containing a widget is
+displayed, and whenever the layout of the window changes, GTK asks
+each child widget for its desired size. This request is handled by the
+function, <tt/gtk_dial_size_request()/. Since our widget isn't a
+container widget, and has no real constraints on its size, we just
+return a reasonable default value.
 
 <tscreen><verb>
-struct _GtkTypeInfo
+static void 
+gtk_dial_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
 {
-  gchar *type_name;
-  guint object_size;
-  guint class_size;
-  GtkClassInitFunc class_init_func;
-  GtkObjectInitFunc object_init_func;
-  GtkArgSetFunc arg_set_func;
-  GtkArgGetFunc arg_get_func;
-};
+  requisition->width = DIAL_DEFAULT_SIZE;
+  requisition->height = DIAL_DEFAULT_SIZE;
+}
 </verb></tscreen>
 
-The fields of this structure are pretty self-explanatory. We'll ignore
-the <tt/arg_set_func/ and <tt/arg_get_func/ fields here: they have an important, 
-but as yet largely
-unimplemented, role in allowing widget options to be conveniently set
-from interpreted languages. Once GTK has a correctly filled in copy of
-this structure, it knows how to create objects of a particular widget
-type. 
-
-<!-- ----------------------------------------------------------------- -->
-<sect2> The <tt/_class_init()/ function
 <p>
-The <tt/WIDGETNAME_class_init()/ function initializes the fields of
-the widget's class structure, and sets up any signals for the
-class. For our Tictactoe widget it looks like:
+After all the widgets have requested an ideal size, the layout of the
+window is computed and each child widget is notified of its actual
+size. Usually, this will at least as large as the requested size, but
+if for instance, the user has resized the window, it may occasionally
+be smaller than the requested size. The size notification is handled
+by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
+computing the sizes of some component pieces for future use, this
+routine also does the grunt work of moving the widgets X window into
+the new position and size.
 
 <tscreen><verb>
-
-enum {
-  TICTACTOE_SIGNAL,
-  LAST_SIGNAL
-};
-
-static gint tictactoe_signals[LAST_SIGNAL] = { 0 };
-
 static void
-tictactoe_class_init (TictactoeClass *class)
+gtk_dial_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
 {
-  GtkObjectClass *object_class;
+  GtkDial *dial;
 
-  object_class = (GtkObjectClass*) class;
-  
-  tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe",
-                                        GTK_RUN_FIRST,
-                                        object_class->type,
-                                        GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe),
-                                        gtk_signal_default_marshaller, GTK_TYPE_NONE, 0);
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+  g_return_if_fail (allocation != NULL);
 
+  widget->allocation = *allocation;
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+      dial = GTK_DIAL (widget);
 
-  gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL);
+      gdk_window_move_resize (widget->window,
+                             allocation->x, allocation->y,
+                             allocation->width, allocation->height);
 
-  class->tictactoe = NULL;
+      dial->radius = MAX(allocation->width,allocation->height) * 0.45;
+      dial->pointer_width = dial->radius / 5;
+    }
 }
-</verb></tscreen>
+</verb></tscreen>.
 
-Our widget has just one signal, the <tt/tictactoe/ signal that is
-invoked when a row, column, or diagonal is completely filled in. Not
-every composite widget needs signals, so if you are reading this for
-the first time, you may want to skip to the next section now, as
-things are going to get a bit complicated.
+<!-- ----------------------------------------------------------------- -->
+<sect2> <tt/gtk_dial_expose()/
 
-The function:
+<p>
+As mentioned above, all the drawing of this widget is done in the
+handler for expose events. There's not much to remark on here except
+the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
+three dimensional shading according to the colors stored in the
+widget's style.
 
 <tscreen><verb>
-gint gtk_signal_new( const gchar         *name,
-                     GtkSignalRunType     run_type,
-                     GtkType              object_type,
-                     gint                 function_offset,
-                     GtkSignalMarshaller  marshaller,
-                     GtkType              return_val,
-                     guint                nparams,
-                     ...);
-</verb></tscreen>
+static gint
+gtk_dial_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
+{
+  GtkDial *dial;
+  GdkPoint points[3];
+  gdouble s,c;
+  gdouble theta;
+  gint xc, yc;
+  gint tick_length;
+  gint i;
 
-Creates a new signal. The parameters are:
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-<itemize>
-<item> <tt/name/: The name of the signal.
-<item> <tt/run_type/: Whether the default handler runs before or after
-user handlers. Usually this will be <tt/GTK_RUN_FIRST/, or <tt/GTK_RUN_LAST/,
-although there are other possibilities.
-<item> <tt/object_type/: The ID of the object that this signal applies
-to. (It will also apply to that objects descendents)
-<item> <tt/function_offset/: The offset within the class structure of
-a pointer to the default handler.
-<item> <tt/marshaller/: A function that is used to invoke the signal
-handler. For signal handlers that have no arguments other than the
-object that emitted the signal and user data, we can use the
-pre-supplied marshaller function <tt/gtk_signal_default_marshaller/.
-<item> <tt/return_val/: The type of the return val.
-<item> <tt/nparams/: The number of parameters of the signal handler
-(other than the two default ones mentioned above)
-<item> <tt/.../: The types of the parameters.
-</itemize>
+  if (event->count > 0)
+    return FALSE;
+  
+  dial = GTK_DIAL (widget);
 
-When specifying types, the <tt/GtkType/ enumeration is used:
+  gdk_window_clear_area (widget->window,
+                        0, 0,
+                        widget->allocation.width,
+                        widget->allocation.height);
 
-<tscreen><verb>
-typedef enum
-{
-  GTK_TYPE_INVALID,
-  GTK_TYPE_NONE,
-  GTK_TYPE_CHAR,
-  GTK_TYPE_BOOL,
-  GTK_TYPE_INT,
-  GTK_TYPE_UINT,
-  GTK_TYPE_LONG,
-  GTK_TYPE_ULONG,
-  GTK_TYPE_FLOAT,
-  GTK_TYPE_DOUBLE,
-  GTK_TYPE_STRING,
-  GTK_TYPE_ENUM,
-  GTK_TYPE_FLAGS,
-  GTK_TYPE_BOXED,
-  GTK_TYPE_FOREIGN,
-  GTK_TYPE_CALLBACK,
-  GTK_TYPE_ARGS,
+  xc = widget->allocation.width/2;
+  yc = widget->allocation.height/2;
 
-  GTK_TYPE_POINTER,
+  /* Draw ticks */
 
-  /* it'd be great if the next two could be removed eventually */
-  GTK_TYPE_SIGNAL,
-  GTK_TYPE_C_CALLBACK,
+  for (i=0; i<25; i++)
+    {
+      theta = (i*M_PI/18. - M_PI/6.);
+      s = sin(theta);
+      c = cos(theta);
 
-  GTK_TYPE_OBJECT
+      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
+      
+      gdk_draw_line (widget->window,
+                    widget->style->fg_gc[widget->state],
+                    xc + c*(dial->radius - tick_length),
+                    yc - s*(dial->radius - tick_length),
+                    xc + c*dial->radius,
+                    yc - s*dial->radius);
+    }
 
-} GtkFundamentalType;
-</verb></tscreen>
+  /* Draw pointer */
 
-<tt/gtk_signal_new()/ returns a unique integer identifier for the
-signal, that we store in the <tt/tictactoe_signals/ array, which we
-index using an enumeration. (Conventionally, the enumeration elements
-are the signal name, uppercased, but here there would be a conflict
-with the <tt/TICTACTOE()/ macro, so we called it <tt/TICTACTOE_SIGNAL/
-instead.
+  s = sin(dial->angle);
+  c = cos(dial->angle);
 
-After creating our signals, we need to tell GTK to associate our
-signals with the Tictactoe class. We do that by calling
-<tt/gtk_object_class_add_signals()/. We then set the pointer which
-points to the default handler for the ``tictactoe'' signal to NULL,
-indicating that there is no default action.
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The <tt/_init()/ function.
-<p>
-Each widget class also needs a function to initialize the object
-structure. Usually, this function has the fairly limited role of
-setting the fields of the structure to default values. For composite
-widgets, however, this function also creates the component widgets.
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;
 
-<tscreen><verb>
-static void
-tictactoe_init (Tictactoe *ttt)
-{
-  GtkWidget *table;
-  gint i,j;
+  gtk_draw_polygon (widget->style,
+                   widget->window,
+                   GTK_STATE_NORMAL,
+                   GTK_SHADOW_OUT,
+                   points, 3,
+                   TRUE);
   
-  table = gtk_table_new (3, 3, TRUE);
-  gtk_container_add (GTK_CONTAINER(ttt), table);
-  gtk_widget_show (table);
-
-  for (i=0;i<3; i++)
-    for (j=0;j<3; j++)
-      {
-       ttt->buttons[i][j] = gtk_toggle_button_new ();
-       gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], 
-                                  i, i+1, j, j+1);
-       gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled",
-                           GTK_SIGNAL_FUNC (tictactoe_toggle), ttt);
-       gtk_widget_set_usize (ttt->buttons[i][j], 20, 20);
-       gtk_widget_show (ttt->buttons[i][j]);
-      }
+  return FALSE;
 }
 </verb></tscreen>
 
 <!-- ----------------------------------------------------------------- -->
-<sect2> And the rest...
+<sect2> Event handling
+
 <p>
-There is one more function that every widget (except for base widget
-types like GtkBin that cannot be instantiated) needs to have - the
-function that the user calls to create an object of that type. This is
-conventionally called <tt/WIDGETNAME_new()/. In some
-widgets, though not for the Tictactoe widgets, this function takes
-arguments, and does some setup based on the arguments. The other two
-functions are specific to the Tictactoe widget. 
 
-<tt/tictactoe_clear()/ is a public function that resets all the
-buttons in the widget to the up position. Note the use of
-<tt/gtk_signal_handler_block_by_data()/ to keep our signal handler for
-button toggles from being triggered unnecessarily.
+The rest of the widget's code handles various types of events, and
+isn't too different from what would be found in many GTK
+applications. Two types of events can occur - either the user can
+click on the widget with the mouse and drag to move the pointer, or
+the value of the Adjustment object can change due to some external
+circumstance. 
 
-<tt/tictactoe_toggle()/ is the signal handler that is invoked when the
-user clicks on a button. It checks to see if there are any winning
-combinations that involve the toggled button, and if so, emits
-the "tictactoe" signal.
+<p>
+When the user clicks on the widget, we check to see if the click was
+appropriately near the pointer, and if so, store then button that the
+user clicked with in the <tt/button/ field of the widget
+structure, and grab all mouse events with a call to
+<tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
+value of the control to be recomputed (by the function
+<tt/gtk_dial_update_mouse/). Depending on the policy that has been
+set, "value_changed" events are either generated instantly
+(<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
+<tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
+button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
 
-<tscreen><verb>  
-GtkWidget*
-tictactoe_new ()
+<tscreen><verb>
+static gint
+gtk_dial_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
 {
-  return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ()));
+  GtkDial *dial;
+  gint dx, dy;
+  double s, c;
+  double d_parallel;
+  double d_perpendicular;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  /* Determine if button press was within pointer region - we 
+     do this by computing the parallel and perpendicular distance of
+     the point where the mouse was pressed from the line passing through
+     the pointer */
+  
+  dx = event->x - widget->allocation.width / 2;
+  dy = widget->allocation.height / 2 - event->y;
+  
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  
+  d_parallel = s*dy + c*dx;
+  d_perpendicular = fabs(s*dx - c*dy);
+  
+  if (!dial->button &&
+      (d_perpendicular < dial->pointer_width/2) &&
+      (d_parallel > - dial->pointer_width))
+    {
+      gtk_grab_add (widget);
+
+      dial->button = event->button;
+
+      gtk_dial_update_mouse (dial, event->x, event->y);
+    }
+
+  return FALSE;
 }
 
-void          
-tictactoe_clear (Tictactoe *ttt)
+static gint
+gtk_dial_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
 {
-  int i,j;
+  GtkDial *dial;
 
-  for (i=0;i<3;i++)
-    for (j=0;j<3;j++)
-      {
-       gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
-       gtk_toggle_button_set_state (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]),
-                                    FALSE);
-       gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt);
-      }
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  if (dial->button == event->button)
+    {
+      gtk_grab_remove (widget);
+
+      dial->button = 0;
+
+      if (dial->policy == GTK_UPDATE_DELAYED)
+       gtk_timeout_remove (dial->timer);
+      
+      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
+         (dial->old_value != dial->adjustment->value))
+       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
+
+  return FALSE;
 }
 
-static void
-tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt)
+static gint
+gtk_dial_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
 {
-  int i,k;
+  GtkDial *dial;
+  GdkModifierType mods;
+  gint x, y, mask;
 
-  static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
-                            { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
-                            { 0, 1, 2 }, { 0, 1, 2 } };
-  static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 },
-                            { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 },
-                            { 0, 1, 2 }, { 2, 1, 0 } };
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  int success, found;
+  dial = GTK_DIAL (widget);
 
-  for (k=0; k<8; k++)
+  if (dial->button != 0)
     {
-      success = TRUE;
-      found = FALSE;
+      x = event->x;
+      y = event->y;
 
-      for (i=0;i<3;i++)
-       {
-         success = success &amp;&amp; 
-           GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active;
-         found = found ||
-           ttt->buttons[rwins[k][i]][cwins[k][i]] == widget;
-       }
-      
-      if (success &amp;&amp; found)
+      if (event->is_hint || (event->window != widget->window))
+       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
+
+      switch (dial->button)
        {
-         gtk_signal_emit (GTK_OBJECT (ttt), 
-                          tictactoe_signals[TICTACTOE_SIGNAL]);
+       case 1:
+         mask = GDK_BUTTON1_MASK;
+         break;
+       case 2:
+         mask = GDK_BUTTON2_MASK;
+         break;
+       case 3:
+         mask = GDK_BUTTON3_MASK;
+         break;
+       default:
+         mask = 0;
          break;
        }
-    }
-}
-</verb></tscreen>
 
-And finally, an example program using our Tictactoe widget:
-
-<tscreen><verb>
-#include <gtk/gtk.h>
-#include "tictactoe.h"
+      if (mods & mask)
+       gtk_dial_update_mouse (dial, x,y);
+    }
 
-/* Invoked when a row, column or diagonal is completed */
-void
-win (GtkWidget *widget, gpointer data)
-{
-  g_print ("Yay!\n");
-  tictactoe_clear (TICTACTOE (widget));
+  return FALSE;
 }
 
-int 
-main (int argc, char *argv[])
+static gint
+gtk_dial_timer (GtkDial *dial)
 {
-  GtkWidget *window;
-  GtkWidget *ttt;
-  
-  gtk_init (&amp;argc, &amp;argv);
+  g_return_val_if_fail (dial != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
 
-  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-  
-  gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame");
-  
-  gtk_signal_connect (GTK_OBJECT (window), "destroy",
-                     GTK_SIGNAL_FUNC (gtk_exit), NULL);
-  
-  gtk_container_border_width (GTK_CONTAINER (window), 10);
+  if (dial->policy == GTK_UPDATE_DELAYED)
+    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
-  /* Create a new Tictactoe widget */
-  ttt = tictactoe_new ();
-  gtk_container_add (GTK_CONTAINER (window), ttt);
-  gtk_widget_show (ttt);
+  return FALSE;
+}
 
-  /* And attach to its "tictactoe" signal */
-  gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe",
-                     GTK_SIGNAL_FUNC (win), NULL);
+static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+  gint xc, yc;
+  gfloat old_value;
 
-  gtk_widget_show (window);
-  
-  gtk_main ();
-  
-  return 0;
-}
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-</verb></tscreen>
+  xc = GTK_WIDGET(dial)->allocation.width / 2;
+  yc = GTK_WIDGET(dial)->allocation.height / 2;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Creating a widget from scratch.
+  old_value = dial->adjustment->value;
+  dial->angle = atan2(yc-y, x-xc);
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Introduction
-<p>
-In this section, we'll learn more about how widgets display themselves
-on the screen and interact with events. As an example of this, we'll
-create an analog dial widget with a pointer that the user can drag to
-set the value.
+  if (dial->angle < -M_PI/2.)
+    dial->angle += 2*M_PI;
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Displaying a widget on the screen
-<p>
-There are several steps that are involved in displaying on the screen.
-After the widget is created with a call to <tt/WIDGETNAME_new()/,
-several more functions are needed:
+  if (dial->angle < -M_PI/6)
+    dial->angle = -M_PI/6;
 
-<itemize>
-<item> <tt/WIDGETNAME_realize()/ is responsible for creating an X
-window for the widget if it has one.
-<item> <tt/WIDGETNAME_map()/ is invoked after the user calls
-<tt/gtk_widget_show()/. It is responsible for making sure the widget
-is actually drawn on the screen (<em/mapped/). For a container class,
-it must also make calls to <tt/map()/> functions of any child widgets.
-<item> <tt/WIDGETNAME_draw()/ is invoked when <tt/gtk_widget_draw()/
-is called for the widget or one of its ancestors. It makes the actual
-calls to the drawing functions to draw the widget on the screen. For
-container widgets, this function must make calls to
-<tt/gtk_widget_draw()/ for its child widgets.
-<item> <tt/WIDGETNAME_expose()/ is a handler for expose events for the
-widget. It makes the necessary calls to the drawing functions to draw
-the exposed portion on the screen. For container widgets, this
-function must generate expose events for its child widgets which don't
-have their own windows. (If they have their own windows, then X will
-generate the necessary expose events)
-</itemize>
+  if (dial->angle > 7.*M_PI/6.)
+    dial->angle = 7.*M_PI/6.;
 
-You might notice that the last two functions are quite similar - each
-is responsible for drawing the widget on the screen. In fact many
-types of widgets don't really care about the difference between the
-two. The default <tt/draw()/ function in the widget class simply
-generates a synthetic expose event for the redrawn area. However, some
-types of widgets can save work by distinguishing between the two
-functions. For instance, if a widget has multiple X windows, then
-since expose events identify the exposed window, it can redraw only
-the affected window, which is not possible for calls to <tt/draw()/.
+  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
 
-Container widgets, even if they don't care about the difference for
-themselves, can't simply use the default <tt/draw()/ function because
-their child widgets might care about the difference. However,
-it would be wasteful to duplicate the drawing code between the two
-functions. The convention is that such widgets have a function called
-<tt/WIDGETNAME_paint()/ that does the actual work of drawing the
-widget, that is then called by the <tt/draw()/ and <tt/expose()/
-functions.
+  if (dial->adjustment->value != old_value)
+    {
+      if (dial->policy == GTK_UPDATE_CONTINUOUS)
+       {
+         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+       }
+      else
+       {
+         gtk_widget_draw (GTK_WIDGET(dial), NULL);
 
-In our example approach, since the dial widget is not a container
-widget, and only has a single window, we can take the simplest
-approach and use the default <tt/draw()/ function and only implement
-an <tt/expose()/ function.
+         if (dial->policy == GTK_UPDATE_DELAYED)
+           {
+             if (dial->timer)
+               gtk_timeout_remove (dial->timer);
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The origins of the Dial Widget
-<p>
-Just as all land animals are just variants on the first amphibian that
-crawled up out of the mud, Gtk widgets tend to start off as variants
-of some other, previously written widget.  Thus, although this section
-is entilted ``Creating a Widget from Scratch'', the Dial widget really
-began with the source code for the Range widget. This was picked as a
-starting point because it would be nice if our Dial had the same
-interface as the Scale widgets which are just specialized descendents
-of the Range widget. So, though the source code is presented below in
-finished form, it should not be implied that it was written, <em>deus
-ex machina</em> in this fashion. Also, if you aren't yet familiar with
-how scale widgets work from the application writer's point of view, it
-would be a good idea to look them over before continuing.
+             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+                                            (GtkFunction) gtk_dial_timer,
+                                            (gpointer) dial);
+           }
+       }
+    }
+}
+</verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> The Basics
 <p>
-Quite a bit of our widget should look pretty familiar from the
-Tictactoe widget. First, we have a header file:
+Changes to the Adjustment by external means are communicated to our
+widget by the ``changed'' and ``value_changed'' signals. The handlers
+for these functions call <tt/gtk_dial_update()/ to validate the
+arguments, compute the new pointer angle, and redraw the widget (by
+calling <tt/gtk_widget_draw()/).
 
 <tscreen><verb>
-/* GTK - The GIMP Toolkit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Library General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Library General Public License for more details.
- *
- * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
+static void
+gtk_dial_update (GtkDial *dial)
+{
+  gfloat new_value;
+  
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-#ifndef __GTK_DIAL_H__
-#define __GTK_DIAL_H__
+  new_value = dial->adjustment->value;
+  
+  if (new_value < dial->adjustment->lower)
+    new_value = dial->adjustment->lower;
 
-#include <gdk/gdk.h>
-#include <gtk/gtkadjustment.h>
-#include <gtk/gtkwidget.h>
+  if (new_value > dial->adjustment->upper)
+    new_value = dial->adjustment->upper;
+
+  if (new_value != dial->adjustment->value)
+    {
+      dial->adjustment->value = new_value;
+      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
 
+  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+    (dial->adjustment->upper - dial->adjustment->lower);
 
-#ifdef __cplusplus
-extern "C" {
-#endif /* __cplusplus */
+  gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}
 
+static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
+{
+  GtkDial *dial;
 
-#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
-#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
-#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
+  dial = GTK_DIAL (data);
 
-typedef struct _GtkDial        GtkDial;
-typedef struct _GtkDialClass   GtkDialClass;
+  if ((dial->old_value != adjustment->value) ||
+      (dial->old_lower != adjustment->lower) ||
+      (dial->old_upper != adjustment->upper))
+    {
+      gtk_dial_update (dial);
+
+      dial->old_value = adjustment->value;
+      dial->old_lower = adjustment->lower;
+      dial->old_upper = adjustment->upper;
+    }
+}
 
-struct _GtkDial
+static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
 {
-  GtkWidget widget;
+  GtkDial *dial;
 
-  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
-  guint policy : 2;
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-  /* Button currently pressed or 0 if none */
-  guint8 button;
+  dial = GTK_DIAL (data);
 
-  /* Dimensions of dial components */
-  gint radius;
-  gint pointer_width;
+  if (dial->old_value != adjustment->value)
+    {
+      gtk_dial_update (dial);
 
-  /* ID of update timer, or 0 if none */
-  guint32 timer;
+      dial->old_value = adjustment->value;
+    }
+}
+</verb></tscreen>
 
-  /* Current angle */
-  gfloat angle;
+<!-- ----------------------------------------------------------------- -->
+<sect2> Possible Enhancements
+<p>
 
-  /* Old values from adjustment stored so we know when something changes */
-  gfloat old_value;
-  gfloat old_lower;
-  gfloat old_upper;
+The Dial widget as we've described it so far runs about 670 lines of
+code. Although that might sound like a fair bit, we've really
+accomplished quite a bit with that much code, especially since much of
+that length is headers and boilerplate. However, there are quite a few
+more enhancements that could be made to this widget:
 
-  /* The adjustment object that stores the data for this dial */
-  GtkAdjustment *adjustment;
-};
+<itemize>
+<item> If you try this widget out, you'll find that there is some
+flashing as the pointer is dragged around. This is because the entire
+widget is erased every time the pointer is moved before being
+redrawn. Often, the best way to handle this problem is to draw to an
+offscreen pixmap, then copy the final results onto the screen in one
+step. (The ProgressBar widget draws itself in this fashion.)
 
-struct _GtkDialClass
-{
-  GtkWidgetClass parent_class;
-};
+<item> The user should be able to use the up and down arrow keys to
+increase and decrease the value.
 
+<item> It would be nice if the widget had buttons to increase and
+decrease the value in small or large steps. Although it would be
+possible to use embedded Button widgets for this, we would also like
+the buttons to auto-repeat when held down, as the arrows on a
+scrollbar do. Most of the code to implement this type of behavior can
+be found in the GtkRange widget.
 
-GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
-guint          gtk_dial_get_type               (void);
-GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
-void           gtk_dial_set_update_policy      (GtkDial      *dial,
-                                               GtkUpdateType  policy);
+<item> The Dial widget could be made into a container widget with a
+single child widget positioned at the bottom between the buttons
+mentioned above. The user could then add their choice of a label or
+entry widget to display the current value of the dial.
 
-void           gtk_dial_set_adjustment         (GtkDial      *dial,
-                                               GtkAdjustment *adjustment);
-#ifdef __cplusplus
-}
-#endif /* __cplusplus */
+</itemize>
 
+<!-- ----------------------------------------------------------------- -->
+<sect1> Learning More
 
-#endif /* __GTK_DIAL_H__ */
-</verb></tscreen>
+<p>
+Only a small part of the many details involved in creating widgets
+could be described above. If you want to write your own widgets, the
+best source of examples is the GTK source itself. Ask yourself some
+questions about the widget you want to write: is it a Container
+widget? does it have its own window? is it a modification of an
+existing widget? Then find a similar widget, and start making changes.
+Good luck!
 
-Since there is quite a bit more going on in this widget, than the last
-one, we have more fields in the data structure, but otherwise things
-are pretty similar.
+<!-- ***************************************************************** -->
+<sect>Scribble, A Simple Example Drawing Program
+<!-- ***************************************************************** -->
 
-Next, after including header files, and declaring a few constants,
-we have some functions to provide information about the widget
-and initialize it:
+<!-- ----------------------------------------------------------------- -->
+<sect1> Overview
 
-<tscreen><verb>
-#include <math.h>
-#include <stdio.h>
-#include <gtk/gtkmain.h>
-#include <gtk/gtksignal.h>
+<p>
+In this section, we will build a simple drawing program. In the
+process, we will examine how to handle mouse events, how to draw in a
+window, and how to do drawing better by using a backing pixmap. After
+creating the simple drawing program, we will extend it by adding
+support for XInput devices, such as drawing tablets. GTK provides
+support routines which makes getting extended information, such as
+pressure and tilt, from such devices quite easy.
 
-#include "gtkdial.h"
+<!-- ----------------------------------------------------------------- -->
+<sect1> Event Handling
 
-#define SCROLL_DELAY_LENGTH  300
-#define DIAL_DEFAULT_SIZE 100
+<p>
+The GTK signals we have already discussed are for high-level actions,
+such as a menu item being selected. However, sometimes it is useful to
+learn about lower-level occurrences, such as the mouse being moved, or
+a key being pressed. There are also GTK signals corresponding to these
+low-level <em>events</em>. The handlers for these signals have an
+extra parameter which is a pointer to a structure containing
+information about the event. For instance, motion events handlers are
+passed a pointer to a GdkEventMotion structure which looks (in part)
+like:
 
-/* Forward declararations */
+<tscreen><verb>
+struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  ...
+  guint state;
+  ...
+};
+</verb></tscreen>
 
-[ omitted to save space ]
+<tt/type/ will be set to the event type, in this case
+<tt/GDK_MOTION_NOTIFY/, window is the window in which the event
+occured. <tt/x/ and <tt/y/ give the coordinates of the event,
+and <tt/state/ specifies the modifier state when the event
+occurred (that is, it specifies which modifier keys and mouse buttons
+were pressed.) It is the bitwise OR of some of the following:
 
-/* Local data */
+<tscreen><verb>
+GDK_SHIFT_MASK  
+GDK_LOCK_MASK   
+GDK_CONTROL_MASK
+GDK_MOD1_MASK   
+GDK_MOD2_MASK   
+GDK_MOD3_MASK   
+GDK_MOD4_MASK   
+GDK_MOD5_MASK   
+GDK_BUTTON1_MASK
+GDK_BUTTON2_MASK
+GDK_BUTTON3_MASK
+GDK_BUTTON4_MASK
+GDK_BUTTON5_MASK
+</verb></tscreen>
 
-static GtkWidgetClass *parent_class = NULL;
+<p>
+As for other signals, to determine what happens when an event occurs
+we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
+know which events we want to be notified about. To do this, we call
+the function:
 
-guint
-gtk_dial_get_type ()
-{
-  static guint dial_type = 0;
+<tscreen><verb>
+void gtk_widget_set_events (GtkWidget *widget,
+                            gint      events);
+</verb></tscreen>
 
-  if (!dial_type)
-    {
-      GtkTypeInfo dial_info =
-      {
-       "GtkDial",
-       sizeof (GtkDial),
-       sizeof (GtkDialClass),
-       (GtkClassInitFunc) gtk_dial_class_init,
-       (GtkObjectInitFunc) gtk_dial_init,
-       (GtkArgSetFunc) NULL,
-        (GtkArgGetFunc) NULL,
-      };
+The second field specifies the events we are interested in. It
+is the bitwise OR of constants that specify different types
+of events. For future reference the event types are:
 
-      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
-    }
+<tscreen><verb>
+GDK_EXPOSURE_MASK
+GDK_POINTER_MOTION_MASK
+GDK_POINTER_MOTION_HINT_MASK
+GDK_BUTTON_MOTION_MASK     
+GDK_BUTTON1_MOTION_MASK    
+GDK_BUTTON2_MOTION_MASK    
+GDK_BUTTON3_MOTION_MASK    
+GDK_BUTTON_PRESS_MASK      
+GDK_BUTTON_RELEASE_MASK    
+GDK_KEY_PRESS_MASK         
+GDK_KEY_RELEASE_MASK       
+GDK_ENTER_NOTIFY_MASK      
+GDK_LEAVE_NOTIFY_MASK      
+GDK_FOCUS_CHANGE_MASK      
+GDK_STRUCTURE_MASK         
+GDK_PROPERTY_CHANGE_MASK   
+GDK_PROXIMITY_IN_MASK      
+GDK_PROXIMITY_OUT_MASK     
+</verb></tscreen>
 
-  return dial_type;
-}
+There are a few subtle points that have to be observed when calling
+<tt/gtk_widget_set_events()/. First, it must be called before the X window
+for a GTK widget is created. In practical terms, this means you
+should call it immediately after creating the widget. Second, the
+widget must have an associated X window. For efficiency, many widget
+types do not have their own window, but draw in their parent's window.
+These widgets are:
 
-static void
-gtk_dial_class_init (GtkDialClass *class)
-{
-  GtkObjectClass *object_class;
-  GtkWidgetClass *widget_class;
+<tscreen><verb>
+GtkAlignment
+GtkArrow
+GtkBin
+GtkBox
+GtkImage
+GtkItem
+GtkLabel
+GtkPixmap
+GtkScrolledWindow
+GtkSeparator
+GtkTable
+GtkAspectFrame
+GtkFrame
+GtkVBox
+GtkHBox
+GtkVSeparator
+GtkHSeparator
+</verb></tscreen>
 
-  object_class = (GtkObjectClass*) class;
-  widget_class = (GtkWidgetClass*) class;
+To capture events for these widgets, you need to use an EventBox 
+widget. See the section on   
+<ref id="sec_The_EventBox_Widget" name="The EventBox Widget"> for
+details.
 
-  parent_class = gtk_type_class (gtk_widget_get_type ());
+<p>
+For our drawing program, we want to know when the mouse button is
+pressed and when the mouse is moved, so we specify
+<tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
+want to know when we need to redraw our window, so we specify
+<tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
+Configure event when our window size changes, we don't have to specify
+the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
+automatically specified for all windows.
 
-  object_class->destroy = gtk_dial_destroy;
+<p>
+It turns out, however, that there is a problem with just specifying
+<tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
+motion event to the event queue every time the user moves the mouse.
+Imagine that it takes us 0.1 seconds to handle a motion event, but the
+X server queues a new motion event every 0.05 seconds. We will soon
+get way behind the users drawing. If the user draws for 5 seconds,
+it will take us another 5 seconds to catch up after they release 
+the mouse button! What we would like is to only get one motion
+event for each event we process. The way to do this is to 
+specify <tt/GDK_POINTER_MOTION_HINT_MASK/. 
 
-  widget_class->realize = gtk_dial_realize;
-  widget_class->expose_event = gtk_dial_expose;
-  widget_class->size_request = gtk_dial_size_request;
-  widget_class->size_allocate = gtk_dial_size_allocate;
-  widget_class->button_press_event = gtk_dial_button_press;
-  widget_class->button_release_event = gtk_dial_button_release;
-  widget_class->motion_notify_event = gtk_dial_motion_notify;
-}
+<p>
+When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
+us a motion event the first time the pointer moves after entering
+our window, or after a button press or release event. Subsequent 
+motion events will be suppressed until we explicitely ask for
+the position of the pointer using the function:
 
-static void
-gtk_dial_init (GtkDial *dial)
-{
-  dial->button = 0;
-  dial->policy = GTK_UPDATE_CONTINUOUS;
-  dial->timer = 0;
-  dial->radius = 0;
-  dial->pointer_width = 0;
-  dial->angle = 0.0;
-  dial->old_value = 0.0;
-  dial->old_lower = 0.0;
-  dial->old_upper = 0.0;
-  dial->adjustment = NULL;
-}
+<tscreen><verb>
+GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
+                                         gint            *x,
+                                         gint            *y,
+                                         GdkModifierType *mask);
+</verb></tscreen>
 
-GtkWidget*
-gtk_dial_new (GtkAdjustment *adjustment)
-{
-  GtkDial *dial;
+(There is another function, <tt>gtk_widget_get_pointer()</tt> which
+has a simpler interface, but turns out not to be very useful, since
+it only retrieves the position of the mouse, not whether the buttons
+are pressed.)
 
-  dial = gtk_type_new (gtk_dial_get_type ());
+<p>
+The code to set the events for our window then looks like:
 
-  if (!adjustment)
-    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
+<tscreen><verb>
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                     (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                     (GtkSignalFunc) configure_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                     (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                     (GtkSignalFunc) button_press_event, NULL);
 
-  gtk_dial_set_adjustment (dial, adjustment);
+  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                        | GDK_LEAVE_NOTIFY_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_POINTER_MOTION_HINT_MASK);
+</verb></tscreen>
 
-  return GTK_WIDGET (dial);
-}
+We'll save the "expose_event" and "configure_event" handlers for
+later. The "motion_notify_event" and "button_press_event" handlers
+pretty simple:
 
-static void
-gtk_dial_destroy (GtkObject *object)
+<tscreen><verb>
+static gint
+button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
-  GtkDial *dial;
-
-  g_return_if_fail (object != NULL);
-  g_return_if_fail (GTK_IS_DIAL (object));
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+      draw_brush (widget, event->x, event->y);
 
-  dial = GTK_DIAL (object);
+  return TRUE;
+}
 
-  if (dial->adjustment)
-    gtk_object_unref (GTK_OBJECT (dial->adjustment));
+static gint
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
+{
+  int x, y;
+  GdkModifierType state;
 
-  if (GTK_OBJECT_CLASS (parent_class)->destroy)
-    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+  if (event->is_hint)
+    gdk_window_get_pointer (event->window, &amp;x, &amp;y, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, x, y);
+  
+  return TRUE;
 }
 </verb></tscreen>
 
-Note that this <tt/init()/ function does less than for the Tictactoe
-widget, since this is not a composite widget, and the <tt/new()/
-function does more, since it now has an argument. Also, note that when
-we store a pointer to the Adjustment object, we increment its
-reference count, (and correspondingly decrement when we no longer use
-it) so that GTK can keep track of when it can be safely destroyed.
+<!-- ----------------------------------------------------------------- -->
+<sect1> The DrawingArea Widget, And Drawing
 
 <p>
-Also, there are a few function to manipulate the widget's options:
+We know turn to the process of drawing on the screen. The 
+widget we use for this is the DrawingArea widget. A drawing area
+widget is essentially an X window and nothing more. It is a blank
+canvas in which we can draw whatever we like. A drawing area
+is created using the call:
 
 <tscreen><verb>
-GtkAdjustment*
-gtk_dial_get_adjustment (GtkDial *dial)
-{
-  g_return_val_if_fail (dial != NULL, NULL);
-  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
-
-  return dial->adjustment;
-}
-
-void
-gtk_dial_set_update_policy (GtkDial      *dial,
-                            GtkUpdateType  policy)
-{
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
+GtkWidget* gtk_drawing_area_new        (void);
+</verb></tscreen>
 
-  dial->policy = policy;
-}
+A default size for the widget can be specified by calling:
 
-void
-gtk_dial_set_adjustment (GtkDial      *dial,
-                         GtkAdjustment *adjustment)
-{
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
+<tscreen><verb>
+void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
+                                       gint                 width,
+                                       gint                 height);
+</verb></tscreen>
 
-  if (dial->adjustment)
-    {
-      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
-      gtk_object_unref (GTK_OBJECT (dial->adjustment));
-    }
+This default size can be overriden, as is true for all widgets,
+by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
+be overridden if the user manually resizes the the window containing
+the drawing area.
 
-  dial->adjustment = adjustment;
-  gtk_object_ref (GTK_OBJECT (dial->adjustment));
+<p>
+It should be noted that when we create a DrawingArea widget, we are,
+<em>completely</em> responsible for drawing the contents. If our
+window is obscured then uncovered, we get an exposure event and must
+redraw what was previously hidden.
 
-  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
-                     (GtkSignalFunc) gtk_dial_adjustment_changed,
-                     (gpointer) dial);
-  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
-                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
-                     (gpointer) dial);
+<p>
+Having to remember everything that was drawn on the screen so we
+can properly redraw it can, to say the least, be a nuisance. In
+addition, it can be visually distracting if portions of the
+window are cleared, then redrawn step by step. The solution to
+this problem is to use an offscreen <em>backing pixmap</em>.
+Instead of drawing directly to the screen, we draw to an image
+stored in server memory but not displayed, then when the image
+changes or new portions of the image are displayed, we copy the
+relevant portions onto the screen.
 
-  dial->old_value = adjustment->value;
-  dial->old_lower = adjustment->lower;
-  dial->old_upper = adjustment->upper;
+<p>
+To create an offscreen pixmap, we call the function:
 
-  gtk_dial_update (dial);
-}
+<tscreen><verb>
+GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
+                                        gint        width,
+                                        gint        height,
+                                        gint        depth);
 </verb></tscreen>
 
-<sect2> <tt/gtk_dial_realize()/
+The <tt>window</tt> parameter specifies a GDK window that this pixmap
+takes some of its properties from. <tt>width</tt> and <tt>height</tt>
+specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
+depth</em>, that is the number of bits per pixel, for the new window.
+If the depth is specified as <tt>-1</tt>, it will match the depth
+of <tt>window</tt>.
 
 <p>
-Now we come to some new types of functions. First, we have a function
-that does the work of creating the X window. Notice that a mask is
-passed to the function <tt/gdk_window_new()/ which specifies which fields of
-the GdkWindowAttr structure actually have data in them (the remaining
-fields wll be given default values). Also worth noting is the way the
-event mask of the widget is created. We call
-<tt/gtk_widget_get_events()/ to retrieve the event mask that the user
-has specified for this widget (with <tt/gtk_widget_set_events()/, and
-add the events that we are interested in ourselves.
+We create the pixmap in our "configure_event" handler. This event
+is generated whenever the window changes size, including when it
+is originally created.
+
+<tscreen><verb>
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;
+
+/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+  if (pixmap)
+    gdk_pixmap_unref(pixmap);
+
+  pixmap = gdk_pixmap_new(widget->window,
+                         widget->allocation.width,
+                         widget->allocation.height,
+                         -1);
+  gdk_draw_rectangle (pixmap,
+                     widget->style->white_gc,
+                     TRUE,
+                     0, 0,
+                     widget->allocation.width,
+                     widget->allocation.height);
+
+  return TRUE;
+}
+</verb></tscreen>
+
+The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
+initially to white. We'll say more about that in a moment.
 
 <p>
-After creating the window, we set its style and background, and put a
-pointer to the widget in the user data field of the GdkWindow. This
-last step allows GTK to dispatch events for this window to the correct
-widget.
+Our exposure event handler then simply copies the relevant portion
+of the pixmap onto the screen (we determine the area we need
+to redraw by using the event->area field of the exposure event):
 
 <tscreen><verb>
-static void
-gtk_dial_realize (GtkWidget *widget)
+/* Redraw the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
 {
-  GtkDial *dial;
-  GdkWindowAttr attributes;
-  gint attributes_mask;
+  gdk_draw_pixmap(widget->window,
+                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                 pixmap,
+                 event->area.x, event->area.y,
+                 event->area.x, event->area.y,
+                 event->area.width, event->area.height);
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_DIAL (widget));
+  return FALSE;
+}
+</verb></tscreen>
 
-  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
-  dial = GTK_DIAL (widget);
+We've now seen how to keep the screen up to date with our pixmap, but
+how do we actually draw interesting stuff on our pixmap?  There are a
+large number of calls in GTK's GDK library for drawing on
+<em>drawables</em>. A drawable is simply something that can be drawn
+upon. It can be a window, a pixmap, or a bitmap (a black and white
+image).  We've already seen two such calls above,
+<tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
+complete list is:
 
-  attributes.x = widget->allocation.x;
-  attributes.y = widget->allocation.y;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->allocation.height;
-  attributes.wclass = GDK_INPUT_OUTPUT;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.event_mask = gtk_widget_get_events (widget) | 
-    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
-    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
-    GDK_POINTER_MOTION_HINT_MASK;
-  attributes.visual = gtk_widget_get_visual (widget);
-  attributes.colormap = gtk_widget_get_colormap (widget);
+<tscreen><verb>
+gdk_draw_line ()
+gdk_draw_rectangle ()
+gdk_draw_arc ()
+gdk_draw_polygon ()
+gdk_draw_string ()
+gdk_draw_text ()
+gdk_draw_pixmap ()
+gdk_draw_bitmap ()
+gdk_draw_image ()
+gdk_draw_points ()
+gdk_draw_segments ()
+</verb></tscreen>
 
-  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
-  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
+See the reference documentation or the header file
+<tt>&lt;gdk/gdk.h&gt;</tt> for further details on these functions.
+These functions all share the same first two arguments. The first
+argument is the drawable to draw upon, the second argument is a
+<em>graphics context</em> (GC). 
 
-  widget->style = gtk_style_attach (widget->style, widget->window);
+<p>
+A graphics context encapsulates information about things such as
+foreground and background color and line width. GDK has a full set of
+functions for creating and modifying graphics contexts, but to keep
+things simple we'll just use predefined graphics contexts. Each widget
+has an associated style. (Which can be modified in a gtkrc file, see
+the section GTK's rc file.) This, among other things, stores a number
+of graphics contexts. Some examples of accessing these graphics
+contexts are:
 
-  gdk_window_set_user_data (widget->window, widget);
+<tscreen><verb>
+widget->style->white_gc
+widget->style->black_gc
+widget->style->fg_gc[GTK_STATE_NORMAL]
+widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
+</verb></tscreen>
 
-  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
-}
+The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
+<tt>light_gc</tt> are indexed by a parameter of type
+<tt>GtkStateType</tt> which can take on the values:
+
+<tscreen><verb>
+GTK_STATE_NORMAL,
+GTK_STATE_ACTIVE,
+GTK_STATE_PRELIGHT,
+GTK_STATE_SELECTED,
+GTK_STATE_INSENSITIVE
 </verb></tscreen>
 
-<sect2> Size negotiation
+For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
+color is white and the default background color, dark blue.
 
 <p>
-Before the first time that the window containing a widget is
-displayed, and whenever the layout of the window changes, GTK asks
-each child widget for its desired size. This request is handled by the
-function, <tt/gtk_dial_size_request()/. Since our widget isn't a
-container widget, and has no real constraints on its size, we just
-return a reasonable default value.
+Our function <tt>draw_brush()</tt>, which does the actual drawing
+on the screen, is then:
 
 <tscreen><verb>
-static void 
-gtk_dial_size_request (GtkWidget      *widget,
-                      GtkRequisition *requisition)
+/* Draw a rectangle on the screen */
+static void
+draw_brush (GtkWidget *widget, gdouble x, gdouble y)
 {
-  requisition->width = DIAL_DEFAULT_SIZE;
-  requisition->height = DIAL_DEFAULT_SIZE;
+  GdkRectangle update_rect;
+
+  update_rect.x = x - 5;
+  update_rect.y = y - 5;
+  update_rect.width = 10;
+  update_rect.height = 10;
+  gdk_draw_rectangle (pixmap,
+                     widget->style->black_gc,
+                     TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
 }
 </verb></tscreen>
 
-<p>
-After all the widgets have requested an ideal size, the layout of the
-window is computed and each child widget is notified of its actual
-size. Usually, this will at least as large as the requested size, but
-if for instance, the user has resized the window, it may occasionally
-be smaller than the requested size. The size notification is handled
-by the function <tt/gtk_dial_size_allocate()/. Notice that as well as
-computing the sizes of some component pieces for future use, this
-routine also does the grunt work of moving the widgets X window into
-the new position and size.
+After we draw the rectangle representing the brush onto the pixmap,
+we call the function:
 
 <tscreen><verb>
-static void
-gtk_dial_size_allocate (GtkWidget     *widget,
-                       GtkAllocation *allocation)
-{
-  GtkDial *dial;
+void       gtk_widget_draw                (GtkWidget           *widget,
+                                          GdkRectangle        *area);
+</verb></tscreen>
 
-  g_return_if_fail (widget != NULL);
-  g_return_if_fail (GTK_IS_DIAL (widget));
-  g_return_if_fail (allocation != NULL);
+which notifies X that the area given by the <tt>area</tt> parameter
+needs to be updated. X will eventually generate an expose event
+(possibly combining the areas passed in several calls to
+<tt>gtk_widget_draw()</tt>) which will cause our expose event handler
+to copy the relevant portions to the screen.
 
-  widget->allocation = *allocation;
-  if (GTK_WIDGET_REALIZED (widget))
-    {
-      dial = GTK_DIAL (widget);
+<p>
+We have now covered the entire drawing program except for a few
+mundane details like creating the main window. The complete
+source code is available from the location from which you got
+this tutorial, or from:
 
-      gdk_window_move_resize (widget->window,
-                             allocation->x, allocation->y,
-                             allocation->width, allocation->height);
+<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
+name="http://www.gtk.org/~otaylor/gtk/tutorial/">
 
-      dial->radius = MAX(allocation->width,allocation->height) * 0.45;
-      dial->pointer_width = dial->radius / 5;
-    }
-}
-</verb></tscreen>.
 
 <!-- ----------------------------------------------------------------- -->
-<sect2> <tt/gtk_dial_expose()/
+<sect1> Adding XInput support
 
 <p>
-As mentioned above, all the drawing of this widget is done in the
-handler for expose events. There's not much to remark on here except
-the use of the function <tt/gtk_draw_polygon/ to draw the pointer with
-three dimensional shading according to the colors stored in the
-widget's style.
-
-<tscreen><verb>
-static gint
-gtk_dial_expose (GtkWidget      *widget,
-                GdkEventExpose *event)
-{
-  GtkDial *dial;
-  GdkPoint points[3];
-  gdouble s,c;
-  gdouble theta;
-  gint xc, yc;
-  gint tick_length;
-  gint i;
 
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  if (event->count > 0)
-    return FALSE;
-  
-  dial = GTK_DIAL (widget);
+It is now possible to buy quite inexpensive input devices such 
+as drawing tablets, which allow drawing with a much greater
+ease of artistic expression than does a mouse. The simplest way
+to use such devices is simply as a replacement for the mouse,
+but that misses out many of the advantages of these devices,
+such as:
 
-  gdk_window_clear_area (widget->window,
-                        0, 0,
-                        widget->allocation.width,
-                        widget->allocation.height);
+<itemize>
+<item> Pressure sensitivity
+<item> Tilt reporting
+<item> Sub-pixel positioning
+<item> Multiple inputs (for example, a stylus with a point and eraser)
+</itemize>
 
-  xc = widget->allocation.width/2;
-  yc = widget->allocation.height/2;
+For information about the XInput extension, see the <htmlurl
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
+name="XInput-HOWTO">.
 
-  /* Draw ticks */
+<p>
+If we examine the full definition of, for example, the GdkEventMotion
+structure, we see that it has fields to support extended device
+information.
 
-  for (i=0; i<25; i++)
-    {
-      theta = (i*M_PI/18. - M_PI/6.);
-      s = sin(theta);
-      c = cos(theta);
+<tscreen><verb>
+struct _GdkEventMotion
+{
+  GdkEventType type;
+  GdkWindow *window;
+  guint32 time;
+  gdouble x;
+  gdouble y;
+  gdouble pressure;
+  gdouble xtilt;
+  gdouble ytilt;
+  guint state;
+  gint16 is_hint;
+  GdkInputSource source;
+  guint32 deviceid;
+};
+</verb></tscreen>
 
-      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
-      
-      gdk_draw_line (widget->window,
-                    widget->style->fg_gc[widget->state],
-                    xc + c*(dial->radius - tick_length),
-                    yc - s*(dial->radius - tick_length),
-                    xc + c*dial->radius,
-                    yc - s*dial->radius);
-    }
+<tt/pressure/ gives the pressure as a floating point number between
+0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between 
+-1 and 1, corresponding to the degree of tilt in each direction.
+<tt/source/ and <tt/deviceid/ specify the device for which the
+event occurred in two different ways. <tt/source/ gives some simple
+information about the type of device. It can take the enumeration
+values.
 
-  /* Draw pointer */
+<tscreen><verb>
+GDK_SOURCE_MOUSE
+GDK_SOURCE_PEN
+GDK_SOURCE_ERASER
+GDK_SOURCE_CURSOR
+</verb></tscreen>
 
-  s = sin(dial->angle);
-  c = cos(dial->angle);
+<tt/deviceid/ specifies a unique numeric ID for the device. This can
+be used to find out further information about the device using the
+<tt/gdk_input_list_devices()/ call (see below). The special value
+<tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
+the mouse.)
 
+<sect2> Enabling extended device information
 
-  points[0].x = xc + s*dial->pointer_width/2;
-  points[0].y = yc + c*dial->pointer_width/2;
-  points[1].x = xc + c*dial->radius;
-  points[1].y = yc - s*dial->radius;
-  points[2].x = xc - s*dial->pointer_width/2;
-  points[2].y = yc - c*dial->pointer_width/2;
+<p>
+To let GTK know about our interest in the extended device information,
+we merely have to add a single line to our program:
 
-  gtk_draw_polygon (widget->style,
-                   widget->window,
-                   GTK_STATE_NORMAL,
-                   GTK_SHADOW_OUT,
-                   points, 3,
-                   TRUE);
-  
-  return FALSE;
-}
+<tscreen><verb>
+gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
 </verb></tscreen>
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Event handling
-
-<p>
-
-The rest of the widget's code handles various types of events, and
-isn't too different from what would be found in many GTK
-applications. Two types of events can occur - either the user can
-click on the widget with the mouse and drag to move the pointer, or
-the value of the Adjustment object can change due to some external
-circumstance. 
+By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
+we are interested in extension events, but only if we don't have
+to draw our own cursor. See the section <ref
+id="sec_Further_Sophistications" name="Further Sophistications"> below
+for more information about drawing the cursor. We could also 
+give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing 
+to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
+back to the default condition.
 
 <p>
-When the user clicks on the widget, we check to see if the click was
-appropriately near the pointer, and if so, store then button that the
-user clicked with in the <tt/button/ field of the widget
-structure, and grab all mouse events with a call to
-<tt/gtk_grab_add()/. Subsequent motion of the mouse causes the
-value of the control to be recomputed (by the function
-<tt/gtk_dial_update_mouse/). Depending on the policy that has been
-set, "value_changed" events are either generated instantly
-(<tt/GTK_UPDATE_CONTINUOUS/), after a delay in a timer added with
-<tt/gtk_timeout_add()/ (<tt/GTK_UPDATE_DELAYED/), or only when the
-button is released (<tt/GTK_UPDATE_DISCONTINUOUS/).
+This is not completely the end of the story however. By default,
+no extension devices are enabled. We need a mechanism to allow
+users to enable and configure their extension devices. GTK provides
+the InputDialog widget to automate this process. The following
+procedure manages an InputDialog widget. It creates the dialog if
+it isn't present, and raises it to the top otherwise.
 
 <tscreen><verb>
-static gint
-gtk_dial_button_press (GtkWidget      *widget,
-                      GdkEventButton *event)
+void
+input_dialog_destroy (GtkWidget *w, gpointer data)
 {
-  GtkDial *dial;
-  gint dx, dy;
-  double s, c;
-  double d_parallel;
-  double d_perpendicular;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+  *((GtkWidget **)data) = NULL;
+}
 
-  dial = GTK_DIAL (widget);
+void
+create_input_dialog ()
+{
+  static GtkWidget *inputd = NULL;
 
-  /* Determine if button press was within pointer region - we 
-     do this by computing the parallel and perpendicular distance of
-     the point where the mouse was pressed from the line passing through
-     the pointer */
-  
-  dx = event->x - widget->allocation.width / 2;
-  dy = widget->allocation.height / 2 - event->y;
-  
-  s = sin(dial->angle);
-  c = cos(dial->angle);
-  
-  d_parallel = s*dy + c*dx;
-  d_perpendicular = fabs(s*dx - c*dy);
-  
-  if (!dial->button &&
-      (d_perpendicular < dial->pointer_width/2) &&
-      (d_parallel > - dial->pointer_width))
+  if (!inputd)
     {
-      gtk_grab_add (widget);
+      inputd = gtk_input_dialog_new();
 
-      dial->button = event->button;
+      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
+                         (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
+      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
+                                "clicked",
+                                (GtkSignalFunc)gtk_widget_hide,
+                                GTK_OBJECT(inputd));
+      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
 
-      gtk_dial_update_mouse (dial, event->x, event->y);
+      gtk_widget_show (inputd);
+    }
+  else
+    {
+      if (!GTK_WIDGET_MAPPED(inputd))
+       gtk_widget_show(inputd);
+      else
+       gdk_window_raise(inputd->window);
     }
-
-  return FALSE;
 }
+</verb></tscreen>
 
-static gint
-gtk_dial_button_release (GtkWidget      *widget,
-                         GdkEventButton *event)
-{
-  GtkDial *dial;
+(You might want to take note of the way we handle this dialog.  By
+connecting to the "destroy" signal, we make sure that we don't keep a
+pointer to dialog around after it is destroyed - that could lead to a
+segfault.)
 
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
+<p>
+The InputDialog has two buttons "Close" and "Save", which by default
+have no actions assigned to them. In the above function we make
+"Close" hide the dialog, hide the "Save" button, since we don't
+implement saving of XInput options in this program.
 
-  dial = GTK_DIAL (widget);
+<sect2> Using extended device information
 
-  if (dial->button == event->button)
-    {
-      gtk_grab_remove (widget);
+<p>
+Once we've enabled the device, we can just use the extended 
+device information in the extra fields of the event structures.
+In fact, it is always safe to use this information since these
+fields will have reasonable default values even when extended
+events are not enabled.
 
-      dial->button = 0;
+<p>
+Once change we do have to make is to call
+<tt/gdk_input_window_get_pointer()/ instead of
+<tt/gdk_window_get_pointer/. This is necessary because
+<tt/gdk_window_get_pointer/ doesn't return the extended device
+information.
 
-      if (dial->policy == GTK_UPDATE_DELAYED)
-       gtk_timeout_remove (dial->timer);
-      
-      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &&
-         (dial->old_value != dial->adjustment->value))
-       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
-    }
+<tscreen><verb>
+void gdk_input_window_get_pointer     (GdkWindow       *window,
+                                      guint32         deviceid,
+                                      gdouble         *x,
+                                      gdouble         *y,
+                                      gdouble         *pressure,
+                                      gdouble         *xtilt,
+                                      gdouble         *ytilt,
+                                      GdkModifierType *mask);
+</verb></tscreen>
 
-  return FALSE;
-}
+When calling this function, we need to specify the device ID as
+well as the window. Usually, we'll get the device ID from the
+<tt/deviceid/ field of an event structure. Again, this function
+will return reasonable values when extension events are not
+enabled. (In this case, <tt/event->deviceid/ will have the value
+<tt/GDK_CORE_POINTER/).
 
+So the basic structure of our button-press and motion event handlers,
+doesn't change much - we just need to add code to deal with the
+extended information.
+
+<tscreen><verb>
 static gint
-gtk_dial_motion_notify (GtkWidget      *widget,
-                        GdkEventMotion *event)
+button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
-  GtkDial *dial;
-  GdkModifierType mods;
-  gint x, y, mask;
-
-  g_return_val_if_fail (widget != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
-  g_return_val_if_fail (event != NULL, FALSE);
-
-  dial = GTK_DIAL (widget);
-
-  if (dial->button != 0)
-    {
-      x = event->x;
-      y = event->y;
-
-      if (event->is_hint || (event->window != widget->window))
-       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
-
-      switch (dial->button)
-       {
-       case 1:
-         mask = GDK_BUTTON1_MASK;
-         break;
-       case 2:
-         mask = GDK_BUTTON2_MASK;
-         break;
-       case 3:
-         mask = GDK_BUTTON3_MASK;
-         break;
-       default:
-         mask = 0;
-         break;
-       }
-
-      if (mods & mask)
-       gtk_dial_update_mouse (dial, x,y);
-    }
+  print_button_press (event->deviceid);
+  
+  if (event->button == 1 &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, event->x, event->y, event->pressure);
 
-  return FALSE;
+  return TRUE;
 }
 
 static gint
-gtk_dial_timer (GtkDial *dial)
+motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
 {
-  g_return_val_if_fail (dial != NULL, FALSE);
-  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
-
-  if (dial->policy == GTK_UPDATE_DELAYED)
-    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+  gdouble x, y;
+  gdouble pressure;
+  GdkModifierType state;
 
-  return FALSE;
+  if (event->is_hint)
+    gdk_input_window_get_pointer (event->window, event->deviceid,
+                                 &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
+  else
+    {
+      x = event->x;
+      y = event->y;
+      pressure = event->pressure;
+      state = event->state;
+    }
+    
+  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
+    draw_brush (widget, event->source, x, y, pressure);
+  
+  return TRUE;
 }
+</verb></tscreen>
+
+We also need to do something with the new information. Our new
+<tt/draw_brush()/ function draws with a different color for
+each <tt/event->source/ and changes the brush size depending
+on the pressure.
 
+<tscreen><verb>
+/* Draw a rectangle on the screen, size depending on pressure,
+   and color on the type of device */
 static void
-gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+draw_brush (GtkWidget *widget, GdkInputSource source,
+           gdouble x, gdouble y, gdouble pressure)
 {
-  gint xc, yc;
-  gfloat old_value;
-
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
-
-  xc = GTK_WIDGET(dial)->allocation.width / 2;
-  yc = GTK_WIDGET(dial)->allocation.height / 2;
-
-  old_value = dial->adjustment->value;
-  dial->angle = atan2(yc-y, x-xc);
-
-  if (dial->angle < -M_PI/2.)
-    dial->angle += 2*M_PI;
-
-  if (dial->angle < -M_PI/6)
-    dial->angle = -M_PI/6;
-
-  if (dial->angle > 7.*M_PI/6.)
-    dial->angle = 7.*M_PI/6.;
-
-  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
-    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
+  GdkGC *gc;
+  GdkRectangle update_rect;
 
-  if (dial->adjustment->value != old_value)
+  switch (source)
     {
-      if (dial->policy == GTK_UPDATE_CONTINUOUS)
-       {
-         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
-       }
-      else
-       {
-         gtk_widget_draw (GTK_WIDGET(dial), NULL);
-
-         if (dial->policy == GTK_UPDATE_DELAYED)
-           {
-             if (dial->timer)
-               gtk_timeout_remove (dial->timer);
-
-             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
-                                            (GtkFunction) gtk_dial_timer,
-                                            (gpointer) dial);
-           }
-       }
+    case GDK_SOURCE_MOUSE:
+      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
+      break;
+    case GDK_SOURCE_PEN:
+      gc = widget->style->black_gc;
+      break;
+    case GDK_SOURCE_ERASER:
+      gc = widget->style->white_gc;
+      break;
+    default:
+      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
     }
+
+  update_rect.x = x - 10 * pressure;
+  update_rect.y = y - 10 * pressure;
+  update_rect.width = 20 * pressure;
+  update_rect.height = 20 * pressure;
+  gdk_draw_rectangle (pixmap, gc, TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
 }
 </verb></tscreen>
 
+<sect2> Finding out more about a device
+
 <p>
-Changes to the Adjustment by external means are communicated to our
-widget by the ``changed'' and ``value_changed'' signals. The handlers
-for these functions call <tt/gtk_dial_update()/ to validate the
-arguments, compute the new pointer angle, and redraw the widget (by
-calling <tt/gtk_widget_draw()/).
+As an example of how to find out more about a device, our program
+will print the name of the device that generates each button
+press. To find out the name of a device, we call the function:
 
 <tscreen><verb>
-static void
-gtk_dial_update (GtkDial *dial)
-{
-  gfloat new_value;
-  
-  g_return_if_fail (dial != NULL);
-  g_return_if_fail (GTK_IS_DIAL (dial));
-
-  new_value = dial->adjustment->value;
-  
-  if (new_value < dial->adjustment->lower)
-    new_value = dial->adjustment->lower;
+GList *gdk_input_list_devices               (void);
+</verb></tscreen>
 
-  if (new_value > dial->adjustment->upper)
-    new_value = dial->adjustment->upper;
+which returns a GList (a linked list type from the glib library)
+of GdkDeviceInfo structures. The GdkDeviceInfo strucure is defined
+as:
 
-  if (new_value != dial->adjustment->value)
-    {
-      dial->adjustment->value = new_value;
-      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
-    }
+<tscreen><verb>
+struct _GdkDeviceInfo
+{
+  guint32 deviceid;
+  gchar *name;
+  GdkInputSource source;
+  GdkInputMode mode;
+  gint has_cursor;
+  gint num_axes;
+  GdkAxisUse *axes;
+  gint num_keys;
+  GdkDeviceKey *keys;
+};
+</verb></tscreen>
 
-  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
-    (dial->adjustment->upper - dial->adjustment->lower);
+Most of these fields are configuration information that you
+can ignore unless you are implemented XInput configuration
+saving. The we are interested in here is <tt/name/ which is
+simply the name that X assigns to the device. The other field
+that isn't configuration information is <tt/has_cursor/. If
+<tt/has_cursor/ is false, then we we need to draw our own
+cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
+we don't have to worry about this.
 
-  gtk_widget_draw (GTK_WIDGET(dial), NULL);
-}
+<p>
+Our <tt/print_button_press()/ function simply iterates through
+the returned list until it finds a match, then prints out
+the name of the device.
 
+<tscreen><verb>
 static void
-gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
-                             gpointer       data)
+print_button_press (guint32 deviceid)
 {
-  GtkDial *dial;
-
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+  GList *tmp_list;
 
-  dial = GTK_DIAL (data);
+  /* gdk_input_list_devices returns an internal list, so we shouldn't
+     free it afterwards */
+  tmp_list = gdk_input_list_devices();
 
-  if ((dial->old_value != adjustment->value) ||
-      (dial->old_lower != adjustment->lower) ||
-      (dial->old_upper != adjustment->upper))
+  while (tmp_list)
     {
-      gtk_dial_update (dial);
+      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
 
-      dial->old_value = adjustment->value;
-      dial->old_lower = adjustment->lower;
-      dial->old_upper = adjustment->upper;
+      if (info->deviceid == deviceid)
+       {
+         printf("Button press on device '%s'\n", info->name);
+         return;
+       }
+
+      tmp_list = tmp_list->next;
     }
 }
+</verb></tscreen>
 
-static void
-gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
-                                   gpointer       data)
-{
-  GtkDial *dial;
+That completes the changes to ``XInputize'' our program. As with
+the first version, the complete source is available at the location
+from which you got this tutorial, or from:
 
-  g_return_if_fail (adjustment != NULL);
-  g_return_if_fail (data != NULL);
+<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
+name="http://www.gtk.org/~otaylor/gtk/tutorial/">
 
-  dial = GTK_DIAL (data);
 
-  if (dial->old_value != adjustment->value)
-    {
-      gtk_dial_update (dial);
+<sect2> Further sophistications <label id="sec_Further_Sophistications">
 
-      dial->old_value = adjustment->value;
-    }
-}
-</verb></tscreen>
+<p>
+Although our program now supports XInput quite well, it lacks some
+features we would want in a full-featured application. First, the user
+probably doesn't want to have to configure their device each time they
+run the program, so we should allow them to save the device
+configuration. This is done by iterating through the return of
+<tt/gdk_input_list_devices()/ and writing out the configuration to a
+file.
 
-<!-- ----------------------------------------------------------------- -->
-<sect2> Possible Enhancements
 <p>
+To restore the state next time the program is run, GDK provides
+functions to change device configuration:
 
-The Dial widget as we've described it so far runs about 670 lines of
-code. Although that might sound like a fair bit, we've really
-accomplished quite a bit with that much code, especially since much of
-that length is headers and boilerplate. However, there are quite a few
-more enhancements that could be made to this widget:
+<tscreen><verb>
+gdk_input_set_extension_events()
+gdk_input_set_source()
+gdk_input_set_mode()
+gdk_input_set_axes()
+gdk_input_set_key()
+</verb></tscreen>
 
-<itemize>
-<item> If you try this widget out, you'll find that there is some
-flashing as the pointer is dragged around. This is because the entire
-widget is erased every time the pointer is moved before being
-redrawn. Often, the best way to handle this problem is to draw to an
-offscreen pixmap, then copy the final results onto the screen in one
-step. (The ProgressBar widget draws itself in this fashion.)
+(The list returned from <tt/gdk_input_list_devices()/ should not be
+modified directly.) An example of doing this can be found in the
+drawing program gsumi. (Available from <htmlurl
+url="http://www.msc.cornell.edu/~otaylor/gsumi/"
+name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
+would be nice to have a standard way of doing this for all
+applications. This probably belongs at a slightly higher level than
+GTK, perhaps in the GNOME library.
 
-<item> The user should be able to use the up and down arrow keys to
-increase and decrease the value.
+<p>
+Another major ommission that we have mentioned above is the lack of
+cursor drawing. Platforms other than XFree86 currently do not allow
+simultaneously using a device as both the core pointer and directly by
+an application. See the <url
+url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
+name="XInput-HOWTO"> for more information about this. This means that
+applications that want to support the widest audience need to draw
+their own cursor.
 
-<item> It would be nice if the widget had buttons to increase and
-decrease the value in small or large steps. Although it would be
-possible to use embedded Button widgets for this, we would also like
-the buttons to auto-repeat when held down, as the arrows on a
-scrollbar do. Most of the code to implement this type of behavior can
-be found in the GtkRange widget.
+<p>
+An application that draws it's own cursor needs to do two things:
+determine if the current device needs a cursor drawn or not, and
+determine if the current device is in proximity. (If the current
+device is a drawing tablet, it's a nice touch to make the cursor 
+disappear when the stylus is lifted from the tablet. When the
+device is touching the stylus, that is called "in proximity.")
+The first is done by searching the device list, as we did
+to find out the device name. The second is achieved by selecting
+"proximity_out" events. An example of drawing one's own cursor is
+found in the 'testinput' program found in the GTK distribution.
 
-<item> The Dial widget could be made into a container widget with a
-single child widget positioned at the bottom between the buttons
-mentioned above. The user could then add their choice of a label or
-entry widget to display the current value of the dial.
+<!-- ***************************************************************** -->
+<sect>Tips For Writing GTK Applications
+<!-- ***************************************************************** -->
 
-</itemize>
+<p>
+This section is simply a gathering of wisdom, general style guidelines and hints to
+creating good GTK applications. It is totally useless right now cause it's
+only a topic sentence :)
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Learning More
+Use GNU autoconf and automake!  They are your friends :)  I am planning to
+make a quick intro on them here.
+
+<!-- ***************************************************************** -->
+<sect>Contributing
+<!-- ***************************************************************** -->
 
 <p>
-Only a small part of the many details involved in creating widgets
-could be described above. If you want to write your own widgets, the
-best source of examples is the GTK source itself. Ask yourself some
-questions about the widget you want to write: is it a Container
-widget? does it have its own window? is it a modification of an
-existing widget? Then find a similar widget, and start making changes.
-Good luck!
+This document, like so much other great software out there, was created for
+free by volunteers.  If you are at all knowledgeable about any aspect of GTK
+that does not already have documentation, please consider contributing to
+this document.
+<p>
+If you do decide to contribute, please mail your text to Tony Gale, 
+<tt><htmlurl url="mailto:gale@gtk.org"
+name="gale@gtk.org"></tt>. Also, be aware that the entirety of this 
+document is free, and any addition by yourself must also be free.  That is, 
+people may use any portion of your examples in their programs, and copies 
+of this document may be distributed at will etc.
+<p>
+Thank you.
 
 <!-- ***************************************************************** -->
-<sect>Scribble, A Simple Example Drawing Program
+<sect>Credits
 <!-- ***************************************************************** -->
+<p>
+I would like to thank the following for their contributions to this text.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Overview
+<itemize>
+<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
+name="chamele0n@geocities.com"></tt> for the menus tutorial.                         
 
-<p>
-In this section, we will build a simple drawing program. In the
-process, we will examine how to handle mouse events, how to draw in a
-window, and how to do drawing better by using a backing pixmap. After
-creating the simple drawing program, we will extend it by adding
-support for XInput devices, such as drawing tablets. GTK provides
-support routines which makes getting extended information, such as
-pressure and tilt, from such devices quite easy.
+<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
+name="raph@acm.org"></tt>
+for hello world ala GTK, widget packing, and general all around wisdom.
+He's also generously donated a home for this tutorial.
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Event Handling
+<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
+name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program.. 
+and the ability to make it :)
 
-<p>
-The GTK signals we have already discussed are for high-level actions,
-such as a menu item being selected. However, sometimes it is useful to
-learn about lower-level occurrences, such as the mouse being moved, or
-a key being pressed. There are also GTK signals corresponding to these
-low-level <em>events</em>. The handlers for these signals have an
-extra parameter which is a pointer to a structure containing
-information about the event. For instance, motion events handlers are
-passed a pointer to a GdkEventMotion structure which looks (in part)
-like:
+<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
+name="werner.koch@guug.de"></tt> for converting the original plain text to
+SGML, and the widget class hierarchy.
 
-<tscreen><verb>
-struct _GdkEventMotion
-{
-  GdkEventType type;
-  GdkWindow *window;
-  guint32 time;
-  gdouble x;
-  gdouble y;
-  ...
-  guint state;
-  ...
-};
-</verb></tscreen>
+<item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
+name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code, and
+the table packing tutorial.
 
-<tt/type/ will be set to the event type, in this case
-<tt/GDK_MOTION_NOTIFY/, window is the window in which the event
-occured. <tt/x/ and <tt/y/ give the coordinates of the event,
-and <tt/state/ specifies the modifier state when the event
-occurred (that is, it specifies which modifier keys and mouse buttons
-were pressed.) It is the bitwise OR of some of the following:
+<item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
+name="owt1@cornell.edu"></tt> for the EventBox widget section (and
+the patch to the distro).  He's also responsible for the selections code and
+tutorial, as well as the sections on writing your own GTK widgets, and the
+example application.  Thanks a lot Owen for all you help!
 
-<tscreen><verb>
-GDK_SHIFT_MASK  
-GDK_LOCK_MASK   
-GDK_CONTROL_MASK
-GDK_MOD1_MASK   
-GDK_MOD2_MASK   
-GDK_MOD3_MASK   
-GDK_MOD4_MASK   
-GDK_MOD5_MASK   
-GDK_BUTTON1_MASK
-GDK_BUTTON2_MASK
-GDK_BUTTON3_MASK
-GDK_BUTTON4_MASK
-GDK_BUTTON5_MASK
-</verb></tscreen>
+<item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
+name="mvboom42@calvin.edu"></tt> for his wonderful work on the Notebook,
+Progress Bar, Dialogs, and File selection widgets.  Thanks a lot Mark!
+You've been a great help.
 
-<p>
-As for other signals, to determine what happens when an event occurs
-we call <tt>gtk_signal_connect()</tt>. But we also need let GTK
-know which events we want to be notified about. To do this, we call
-the function:
+<item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
+name="timj@psynet.net"></tt> for his great job on the Lists Widget.
+Thanks Tim :)
 
-<tscreen><verb>
-void gtk_widget_set_events (GtkWidget *widget,
-                            gint      events);
-</verb></tscreen>
+<item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
+name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap tutorial.
 
-The second field specifies the events we are interested in. It
-is the bitwise OR of constants that specify different types
-of events. For future reference the event types are:
+<item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
+name="johnsonm@redhat.com"></tt> for info and code for popup menus. 
 
-<tscreen><verb>
-GDK_EXPOSURE_MASK
-GDK_POINTER_MOTION_MASK
-GDK_POINTER_MOTION_HINT_MASK
-GDK_BUTTON_MOTION_MASK     
-GDK_BUTTON1_MOTION_MASK    
-GDK_BUTTON2_MOTION_MASK    
-GDK_BUTTON3_MOTION_MASK    
-GDK_BUTTON_PRESS_MASK      
-GDK_BUTTON_RELEASE_MASK    
-GDK_KEY_PRESS_MASK         
-GDK_KEY_RELEASE_MASK       
-GDK_ENTER_NOTIFY_MASK      
-GDK_LEAVE_NOTIFY_MASK      
-GDK_FOCUS_CHANGE_MASK      
-GDK_STRUCTURE_MASK         
-GDK_PROPERTY_CHANGE_MASK   
-GDK_PROXIMITY_IN_MASK      
-GDK_PROXIMITY_OUT_MASK     
-</verb></tscreen>
+</itemize>
+<p>
+And to all of you who commented and helped refine this document.
+<p>
+Thanks.
 
-There are a few subtle points that have to be observed when calling
-<tt/gtk_widget_set_events()/. First, it must be called before the X window
-for a GTK widget is created. In practical terms, this means you
-should call it immediately after creating the widget. Second, the
-widget must have an associated X window. For efficiency, many widget
-types do not have their own window, but draw in their parent's window.
-These widgets are:
+<!-- ***************************************************************** -->
+<sect> Tutorial Copyright and Permissions Notice
+<!-- ***************************************************************** -->
 
-<tscreen><verb>
-GtkAlignment
-GtkArrow
-GtkBin
-GtkBox
-GtkImage
-GtkItem
-GtkLabel
-GtkPixmap
-GtkScrolledWindow
-GtkSeparator
-GtkTable
-GtkAspectFrame
-GtkFrame
-GtkVBox
-GtkHBox
-GtkVSeparator
-GtkHSeparator
-</verb></tscreen>
+<p>
+The GTK Tutorial is Copyright (C) 1997 Ian Main. 
 
-To capture events for these widgets, you need to use an EventBox 
-widget. See the section on   
-<ref id="sec_The_EventBox_Widget" name="The EventBox Widget"> for
-details.
+Copyright (C) 1998 Tony Gale.
+<p>
+Permission is granted to make and distribute verbatim copies of this 
+manual provided the copyright notice and this permission notice are 
+preserved on all copies.
+<P>Permission is granted to copy and distribute modified versions of 
+this document under the conditions for verbatim copying, provided that 
+this copyright notice is included exactly as in the original,
+and that the entire resulting derived work is distributed under 
+the terms of a permission notice identical to this one.
+<P>Permission is granted to copy and distribute translations of this 
+document into another language, under the above conditions for modified 
+versions.
+<P>If you are intending to incorporate this document into a published 
+work, please contact the maintainer, and we will make an effort 
+to ensure that you have the most up to date information available.
+<P>There is no guarentee that this document lives up to its intended
+purpose.  This is simply provided as a free resource.  As such,
+the authors and maintainers of the information provided within can
+not make any guarentee that the information is even accurate.
 
-<p>
-For our drawing program, we want to know when the mouse button is
-pressed and when the mouse is moved, so we specify
-<tt/GDK_POINTER_MOTION_MASK/ and <tt/GDK_BUTTON_PRESS_MASK/. We also
-want to know when we need to redraw our window, so we specify
-<tt/GDK_EXPOSURE_MASK/. Although we want to be notified via a
-Configure event when our window size changes, we don't have to specify
-the corresponding <tt/GDK_STRUCTURE_MASK/ flag, because it is
-automatically specified for all windows.
+<!-- ***************************************************************** -->
+<appendix>
+<!-- ***************************************************************** -->
 
+<!-- ***************************************************************** -->
+<sect> Code Examples
+<!-- ***************************************************************** -->
 <p>
-It turns out, however, that there is a problem with just specifying
-<tt/GDK_POINTER_MOTION_MASK/. This will cause the server to add a new
-motion event to the event queue every time the user moves the mouse.
-Imagine that it takes us 0.1 seconds to handle a motion event, but the
-X server queues a new motion event every 0.05 seconds. We will soon
-get way behind the users drawing. If the user draws for 5 seconds,
-it will take us another 5 seconds to catch up after they release 
-the mouse button! What we would like is to only get one motion
-event for each event we process. The way to do this is to 
-specify <tt/GDK_POINTER_MOTION_HINT_MASK/. 
+Below are the code examples that are used in the above text
+which are not included in complete form elsewhere.
 
+<!-- ----------------------------------------------------------------- -->
+<sect1> Scribble
 <p>
-When we specify <tt/GDK_POINTER_MOTION_HINT_MASK/, the server sends
-us a motion event the first time the pointer moves after entering
-our window, or after a button press or release event. Subsequent 
-motion events will be suppressed until we explicitely ask for
-the position of the pointer using the function:
-
 <tscreen><verb>
-GdkWindow*    gdk_window_get_pointer     (GdkWindow       *window,
-                                         gint            *x,
-                                         gint            *y,
-                                         GdkModifierType *mask);
-</verb></tscreen>
+/* example-start scribble-simple scribble-simple.c */
 
-(There is another function, <tt>gtk_widget_get_pointer()</tt> which
-has a simpler interface, but turns out not to be very useful, since
-it only retrieves the position of the mouse, not whether the buttons
-are pressed.)
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
 
-<p>
-The code to set the events for our window then looks like:
+#include <gtk/gtk.h>
 
-<tscreen><verb>
-  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
-                     (GtkSignalFunc) expose_event, NULL);
-  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
-                     (GtkSignalFunc) configure_event, NULL);
-  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
-                     (GtkSignalFunc) motion_notify_event, NULL);
-  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
-                     (GtkSignalFunc) button_press_event, NULL);
+/* Backing pixmap for drawing area */
+static GdkPixmap *pixmap = NULL;
 
-  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
-                        | GDK_LEAVE_NOTIFY_MASK
-                        | GDK_BUTTON_PRESS_MASK
-                        | GDK_POINTER_MOTION_MASK
-                        | GDK_POINTER_MOTION_HINT_MASK);
-</verb></tscreen>
+/* Create a new backing pixmap of the appropriate size */
+static gint
+configure_event (GtkWidget *widget, GdkEventConfigure *event)
+{
+  if (pixmap)
+    gdk_pixmap_unref(pixmap);
 
-We'll save the "expose_event" and "configure_event" handlers for
-later. The "motion_notify_event" and "button_press_event" handlers
-pretty simple:
+  pixmap = gdk_pixmap_new(widget->window,
+                         widget->allocation.width,
+                         widget->allocation.height,
+                         -1);
+  gdk_draw_rectangle (pixmap,
+                     widget->style->white_gc,
+                     TRUE,
+                     0, 0,
+                     widget->allocation.width,
+                     widget->allocation.height);
+
+  return TRUE;
+}
+
+/* Redraw the screen from the backing pixmap */
+static gint
+expose_event (GtkWidget *widget, GdkEventExpose *event)
+{
+  gdk_draw_pixmap(widget->window,
+                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
+                 pixmap,
+                 event->area.x, event->area.y,
+                 event->area.x, event->area.y,
+                 event->area.width, event->area.height);
+
+  return FALSE;
+}
+
+/* Draw a rectangle on the screen */
+static void
+draw_brush (GtkWidget *widget, gdouble x, gdouble y)
+{
+  GdkRectangle update_rect;
+
+  update_rect.x = x - 5;
+  update_rect.y = y - 5;
+  update_rect.width = 10;
+  update_rect.height = 10;
+  gdk_draw_rectangle (pixmap,
+                     widget->style->black_gc,
+                     TRUE,
+                     update_rect.x, update_rect.y,
+                     update_rect.width, update_rect.height);
+  gtk_widget_draw (widget, &amp;update_rect);
+}
 
-<tscreen><verb>
 static gint
 button_press_event (GtkWidget *widget, GdkEventButton *event)
 {
   if (event->button == 1 &amp;&amp; pixmap != NULL)
-      draw_brush (widget, event->x, event->y);
+    draw_brush (widget, event->x, event->y);
 
   return TRUE;
 }
@@ -9950,732 +11793,776 @@ motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
   
   return TRUE;
 }
+
+void
+quit ()
+{
+  gtk_exit (0);
+}
+
+int
+main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *drawing_area;
+  GtkWidget *vbox;
+
+  GtkWidget *button;
+
+  gtk_init (&amp;argc, &amp;argv);
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_name (window, "Test Input");
+
+  vbox = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), vbox);
+  gtk_widget_show (vbox);
+
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC (quit), NULL);
+
+  /* Create the drawing area */
+
+  drawing_area = gtk_drawing_area_new ();
+  gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200);
+  gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0);
+
+  gtk_widget_show (drawing_area);
+
+  /* Signals used to handle backing pixmap */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event",
+                     (GtkSignalFunc) expose_event, NULL);
+  gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event",
+                     (GtkSignalFunc) configure_event, NULL);
+
+  /* Event signals */
+
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event",
+                     (GtkSignalFunc) motion_notify_event, NULL);
+  gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event",
+                     (GtkSignalFunc) button_press_event, NULL);
+
+  gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK
+                        | GDK_LEAVE_NOTIFY_MASK
+                        | GDK_BUTTON_PRESS_MASK
+                        | GDK_POINTER_MOTION_MASK
+                        | GDK_POINTER_MOTION_HINT_MASK);
+
+  /* .. And a quit button */
+  button = gtk_button_new_with_label ("Quit");
+  gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0);
+
+  gtk_signal_connect_object (GTK_OBJECT (button), "clicked",
+                            GTK_SIGNAL_FUNC (gtk_widget_destroy),
+                            GTK_OBJECT (window));
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+
+  return 0;
+}
+/* example-end */
 </verb></tscreen>
 
 <!-- ----------------------------------------------------------------- -->
-<sect1> The DrawingArea Widget, And Drawing
+<sect1> GtkDial
 
+<!-- ----------------------------------------------------------------- -->
+<sect2> gtkdial.h
 <p>
-We know turn to the process of drawing on the screen. The 
-widget we use for this is the DrawingArea widget. A drawing area
-widget is essentially an X window and nothing more. It is a blank
-canvas in which we can draw whatever we like. A drawing area
-is created using the call:
-
 <tscreen><verb>
-GtkWidget* gtk_drawing_area_new        (void);
-</verb></tscreen>
+/* example-start gtkdial gtkdial.h */
 
-A default size for the widget can be specified by calling:
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#ifndef __GTK_DIAL_H__
+#define __GTK_DIAL_H__
 
-<tscreen><verb>
-void       gtk_drawing_area_size       (GtkDrawingArea      *darea,
-                                       gint                 width,
-                                       gint                 height);
-</verb></tscreen>
 
-This default size can be overriden, as is true for all widgets,
-by calling <tt>gtk_widget_set_usize()</tt>, and that, in turn, can
-be overridden if the user manually resizes the the window containing
-the drawing area.
+#include <gdk/gdk.h>
+#include <gtk/gtkadjustment.h>
+#include <gtk/gtkwidget.h>
 
-<p>
-It should be noted that when we create a DrawingArea widget, we are,
-<em>completely</em> responsible for drawing the contents. If our
-window is obscured then uncovered, we get an exposure event and must
-redraw what was previously hidden.
 
-<p>
-Having to remember everything that was drawn on the screen so we
-can properly redraw it can, to say the least, be a nuisance. In
-addition, it can be visually distracting if portions of the
-window are cleared, then redrawn step by step. The solution to
-this problem is to use an offscreen <em>backing pixmap</em>.
-Instead of drawing directly to the screen, we draw to an image
-stored in server memory but not displayed, then when the image
-changes or new portions of the image are displayed, we copy the
-relevant portions onto the screen.
+#ifdef __cplusplus
+extern "C" {
+#endif /* __cplusplus */
+
+
+#define GTK_DIAL(obj)          GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial)
+#define GTK_DIAL_CLASS(klass)  GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass)
+#define GTK_IS_DIAL(obj)       GTK_CHECK_TYPE (obj, gtk_dial_get_type ())
+
+
+typedef struct _GtkDial        GtkDial;
+typedef struct _GtkDialClass   GtkDialClass;
+
+struct _GtkDial
+{
+  GtkWidget widget;
+
+  /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */
+  guint policy : 2;
+
+  /* Button currently pressed or 0 if none */
+  guint8 button;
 
-<p>
-To create an offscreen pixmap, we call the function:
+  /* Dimensions of dial components */
+  gint radius;
+  gint pointer_width;
 
-<tscreen><verb>
-GdkPixmap* gdk_pixmap_new               (GdkWindow  *window,
-                                        gint        width,
-                                        gint        height,
-                                        gint        depth);
-</verb></tscreen>
+  /* ID of update timer, or 0 if none */
+  guint32 timer;
 
-The <tt>window</tt> parameter specifies a GDK window that this pixmap
-takes some of its properties from. <tt>width</tt> and <tt>height</tt>
-specify the size of the pixmap. <tt>depth</tt> specifies the <em>color
-depth</em>, that is the number of bits per pixel, for the new window.
-If the depth is specified as <tt>-1</tt>, it will match the depth
-of <tt>window</tt>.
+  /* Current angle */
+  gfloat angle;
 
-<p>
-We create the pixmap in our "configure_event" handler. This event
-is generated whenever the window changes size, including when it
-is originally created.
+  /* Old values from adjustment stored so we know when something changes */
+  gfloat old_value;
+  gfloat old_lower;
+  gfloat old_upper;
 
-<tscreen><verb>
-/* Backing pixmap for drawing area */
-static GdkPixmap *pixmap = NULL;
+  /* The adjustment object that stores the data for this dial */
+  GtkAdjustment *adjustment;
+};
 
-/* Create a new backing pixmap of the appropriate size */
-static gint
-configure_event (GtkWidget *widget, GdkEventConfigure *event)
+struct _GtkDialClass
 {
-  if (pixmap)
-    {
-      gdk_pixmap_destroy(pixmap);
-    }
-  pixmap = gdk_pixmap_new(widget->window,
-                         widget->allocation.width,
-                         widget->allocation.height,
-                         -1);
-  gdk_draw_rectangle (pixmap,
-                     widget->style->white_gc,
-                     TRUE,
-                     0, 0,
-                     widget->allocation.width,
-                     widget->allocation.height);
+  GtkWidgetClass parent_class;
+};
 
-  return TRUE;
-}
-</verb></tscreen>
 
-The call to <tt>gdk_draw_rectangle()</tt> clears the pixmap
-initially to white. We'll say more about that in a moment.
+GtkWidget*     gtk_dial_new                    (GtkAdjustment *adjustment);
+guint          gtk_dial_get_type               (void);
+GtkAdjustment* gtk_dial_get_adjustment         (GtkDial      *dial);
+void           gtk_dial_set_update_policy      (GtkDial      *dial,
+                                               GtkUpdateType  policy);
 
-<p>
-Our exposure event handler then simply copies the relevant portion
-of the pixmap onto the screen (we determine the area we need
-to redraw by using the event->area field of the exposure event):
+void           gtk_dial_set_adjustment         (GtkDial      *dial,
+                                               GtkAdjustment *adjustment);
+#ifdef __cplusplus
+}
+#endif /* __cplusplus */
 
-<tscreen><verb>
-/* Refill the screen from the backing pixmap */
-static gint
-expose_event (GtkWidget *widget, GdkEventExpose *event)
-{
-  gdk_draw_pixmap(widget->window,
-                 widget->style->fg_gc[GTK_WIDGET_STATE (widget)],
-                 pixmap,
-                 event->area.x, event->area.y,
-                 event->area.x, event->area.y,
-                 event->area.width, event->area.height);
 
-  return FALSE;
-}
+#endif /* __GTK_DIAL_H__ */
+/* example-end */
 </verb></tscreen>
 
-We've now seen how to keep the screen up to date with our pixmap, but
-how do we actually draw interesting stuff on our pixmap?  There are a
-large number of calls in GTK's GDK library for drawing on
-<em>drawables</em>. A drawable is simply something that can be drawn
-upon. It can be a window, a pixmap, or a bitmap (a black and white
-image).  We've already seen two such calls above,
-<tt>gdk_draw_rectangle()</tt> and <tt>gdk_draw_pixmap()</tt>. The
-complete list is:
-
+<!-- ----------------------------------------------------------------- -->
+<sect2> gtkdial.c
+<p>
 <tscreen><verb>
-gdk_draw_line ()
-gdk_draw_rectangle ()
-gdk_draw_arc ()
-gdk_draw_polygon ()
-gdk_draw_string ()
-gdk_draw_text ()
-gdk_draw_pixmap ()
-gdk_draw_bitmap ()
-gdk_draw_image ()
-gdk_draw_points ()
-gdk_draw_segments ()
-</verb></tscreen>
+/* example-start gtkdial gtkdial.c */
 
-See the reference documentation or the header file
-<tt>&lt;gdk/gdk.h&gt;</tt> for further details on these functions.
-These functions all share the same first two arguments. The first
-argument is the drawable to draw upon, the second argument is a
-<em>graphics context</em> (GC). 
+/* GTK - The GIMP Toolkit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+#include <math.h>
+#include <stdio.h>
+#include <gtk/gtkmain.h>
+#include <gtk/gtksignal.h>
 
-<p>
-A graphics context encapsulates information about things such as
-foreground and background color and line width. GDK has a full set of
-functions for creating and modifying graphics contexts, but to keep
-things simple we'll just use predefined graphics contexts. Each widget
-has an associated style. (Which can be modified in a gtkrc file, see
-the section GTK's rc file.) This, among other things, stores a number
-of graphics contexts. Some examples of accessing these graphics
-contexts are:
+#include "gtkdial.h"
 
-<tscreen><verb>
-widget->style->white_gc
-widget->style->black_gc
-widget->style->fg_gc[GTK_STATE_NORMAL]
-widget->style->bg_gc[GTK_WIDGET_STATE(widget)]
-</verb></tscreen>
+#define SCROLL_DELAY_LENGTH  300
+#define DIAL_DEFAULT_SIZE 100
 
-The fields <tt>fg_gc</tt>, <tt>bg_gc</tt>, <tt>dark_gc</tt>, and
-<tt>light_gc</tt> are indexed by a parameter of type
-<tt>GtkStateType</tt> which can take on the values:
+/* Forward declararations */
 
-<tscreen><verb>
-GTK_STATE_NORMAL,
-GTK_STATE_ACTIVE,
-GTK_STATE_PRELIGHT,
-GTK_STATE_SELECTED,
-GTK_STATE_INSENSITIVE
-</verb></tscreen>
+static void gtk_dial_class_init               (GtkDialClass    *klass);
+static void gtk_dial_init                     (GtkDial         *dial);
+static void gtk_dial_destroy                  (GtkObject        *object);
+static void gtk_dial_realize                  (GtkWidget        *widget);
+static void gtk_dial_size_request             (GtkWidget      *widget,
+                                              GtkRequisition *requisition);
+static void gtk_dial_size_allocate            (GtkWidget     *widget,
+                                              GtkAllocation *allocation);
+static gint gtk_dial_expose                   (GtkWidget        *widget,
+                                               GdkEventExpose   *event);
+static gint gtk_dial_button_press             (GtkWidget        *widget,
+                                               GdkEventButton   *event);
+static gint gtk_dial_button_release           (GtkWidget        *widget,
+                                               GdkEventButton   *event);
+static gint gtk_dial_motion_notify            (GtkWidget        *widget,
+                                               GdkEventMotion   *event);
+static gint gtk_dial_timer                    (GtkDial         *dial);
+
+static void gtk_dial_update_mouse             (GtkDial *dial, gint x, gint y);
+static void gtk_dial_update                   (GtkDial *dial);
+static void gtk_dial_adjustment_changed       (GtkAdjustment    *adjustment,
+                                               gpointer          data);
+static void gtk_dial_adjustment_value_changed (GtkAdjustment    *adjustment,
+                                               gpointer          data);
 
-For instance, the for <tt/GTK_STATE_SELECTED/ the default foreground
-color is white and the default background color, dark blue.
+/* Local data */
 
-<p>
-Our function <tt>draw_brush()</tt>, which does the actual drawing
-on the screen, is then:
+static GtkWidgetClass *parent_class = NULL;
 
-<tscreen><verb>
-/* Draw a rectangle on the screen */
-static void
-draw_brush (GtkWidget *widget, gdouble x, gdouble y)
+guint
+gtk_dial_get_type ()
 {
-  GdkRectangle update_rect;
+  static guint dial_type = 0;
 
-  update_rect.x = x - 5;
-  update_rect.y = y - 5;
-  update_rect.width = 10;
-  update_rect.height = 10;
-  gdk_draw_rectangle (pixmap,
-                     widget->style->black_gc,
-                     TRUE,
-                     update_rect.x, update_rect.y,
-                     update_rect.width, update_rect.height);
-  gtk_widget_draw (widget, &amp;update_rect);
-}
-</verb></tscreen>
+  if (!dial_type)
+    {
+      GtkTypeInfo dial_info =
+      {
+       "GtkDial",
+       sizeof (GtkDial),
+       sizeof (GtkDialClass),
+       (GtkClassInitFunc) gtk_dial_class_init,
+       (GtkObjectInitFunc) gtk_dial_init,
+       (GtkArgSetFunc) NULL,
+       (GtkArgGetFunc) NULL,
+      };
 
-After we draw the rectangle representing the brush onto the pixmap,
-we call the function:
+      dial_type = gtk_type_unique (gtk_widget_get_type (), &amp;dial_info);
+    }
 
-<tscreen><verb>
-void       gtk_widget_draw                (GtkWidget           *widget,
-                                          GdkRectangle        *area);
-</verb></tscreen>
+  return dial_type;
+}
 
-which notifies X that the area given by the <tt>area</tt> parameter
-needs to be updated. X will eventually generate an expose event
-(possibly combining the areas passed in several calls to
-<tt>gtk_widget_draw()</tt>) which will cause our expose event handler
-to copy the relevant portions to the screen.
+static void
+gtk_dial_class_init (GtkDialClass *class)
+{
+  GtkObjectClass *object_class;
+  GtkWidgetClass *widget_class;
 
-<p>
-We have now covered the entire drawing program except for a few
-mundane details like creating the main window. The complete
-source code is available from the location from which you got
-this tutorial, or from:
+  object_class = (GtkObjectClass*) class;
+  widget_class = (GtkWidgetClass*) class;
 
-<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
-name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+  parent_class = gtk_type_class (gtk_widget_get_type ());
 
+  object_class->destroy = gtk_dial_destroy;
 
-<!-- ----------------------------------------------------------------- -->
-<sect1> Adding XInput support
+  widget_class->realize = gtk_dial_realize;
+  widget_class->expose_event = gtk_dial_expose;
+  widget_class->size_request = gtk_dial_size_request;
+  widget_class->size_allocate = gtk_dial_size_allocate;
+  widget_class->button_press_event = gtk_dial_button_press;
+  widget_class->button_release_event = gtk_dial_button_release;
+  widget_class->motion_notify_event = gtk_dial_motion_notify;
+}
+
+static void
+gtk_dial_init (GtkDial *dial)
+{
+  dial->button = 0;
+  dial->policy = GTK_UPDATE_CONTINUOUS;
+  dial->timer = 0;
+  dial->radius = 0;
+  dial->pointer_width = 0;
+  dial->angle = 0.0;
+  dial->old_value = 0.0;
+  dial->old_lower = 0.0;
+  dial->old_upper = 0.0;
+  dial->adjustment = NULL;
+}
 
-<p>
+GtkWidget*
+gtk_dial_new (GtkAdjustment *adjustment)
+{
+  GtkDial *dial;
 
-It is now possible to buy quite inexpensive input devices such 
-as drawing tablets, which allow drawing with a much greater
-ease of artistic expression than does a mouse. The simplest way
-to use such devices is simply as a replacement for the mouse,
-but that misses out many of the advantages of these devices,
-such as:
+  dial = gtk_type_new (gtk_dial_get_type ());
 
-<itemize>
-<item> Pressure sensitivity
-<item> Tilt reporting
-<item> Sub-pixel positioning
-<item> Multiple inputs (for example, a stylus with a point and eraser)
-</itemize>
+  if (!adjustment)
+    adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
 
-For information about the XInput extension, see the <htmlurl
-url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
-name="XInput-HOWTO">.
+  gtk_dial_set_adjustment (dial, adjustment);
 
-<p>
-If we examine the full definition of, for example, the GdkEventMotion
-structure, we see that it has fields to support extended device
-information.
+  return GTK_WIDGET (dial);
+}
 
-<tscreen><verb>
-struct _GdkEventMotion
+static void
+gtk_dial_destroy (GtkObject *object)
 {
-  GdkEventType type;
-  GdkWindow *window;
-  guint32 time;
-  gdouble x;
-  gdouble y;
-  gdouble pressure;
-  gdouble xtilt;
-  gdouble ytilt;
-  guint state;
-  gint16 is_hint;
-  GdkInputSource source;
-  guint32 deviceid;
-};
-</verb></tscreen>
-
-<tt/pressure/ gives the pressure as a floating point number between
-0 and 1. <tt/xtilt/ and <tt/ytilt/ can take on values between 
--1 and 1, corresponding to the degree of tilt in each direction.
-<tt/source/ and <tt/deviceid/ specify the device for which the
-event occurred in two different ways. <tt/source/ gives some simple
-information about the type of device. It can take the enumeration
-values.
-
-<tscreen><verb>
-GDK_SOURCE_MOUSE
-GDK_SOURCE_PEN
-GDK_SOURCE_ERASER
-GDK_SOURCE_CURSOR
-</verb></tscreen>
+  GtkDial *dial;
 
-<tt/deviceid/ specifies a unique numeric ID for the device. This can
-be used to find out further information about the device using the
-<tt/gdk_input_list_devices()/ call (see below). The special value
-<tt/GDK_CORE_POINTER/ is used for the core pointer device. (Usually
-the mouse.)
+  g_return_if_fail (object != NULL);
+  g_return_if_fail (GTK_IS_DIAL (object));
 
-<sect2> Enabling extended device information
+  dial = GTK_DIAL (object);
 
-<p>
-To let GTK know about our interest in the extended device information,
-we merely have to add a single line to our program:
+  if (dial->adjustment)
+    gtk_object_unref (GTK_OBJECT (dial->adjustment));
 
-<tscreen><verb>
-gtk_widget_set_extension_events (drawing_area, GDK_EXTENSION_EVENTS_CURSOR);
-</verb></tscreen>
+  if (GTK_OBJECT_CLASS (parent_class)->destroy)
+    (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
 
-By giving the value <tt/GDK_EXTENSION_EVENTS_CURSOR/ we say that
-we are interested in extension events, but only if we don't have
-to draw our own cursor. See the section <ref
-id="sec_Further_Sophistications" name="Further Sophistications"> below
-for more information about drawing the cursor. We could also 
-give the values <tt/GDK_EXTENSION_EVENTS_ALL/ if we were willing 
-to draw our own cursor, or <tt/GDK_EXTENSION_EVENTS_NONE/ to revert
-back to the default condition.
+GtkAdjustment*
+gtk_dial_get_adjustment (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, NULL);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), NULL);
 
-<p>
-This is not completely the end of the story however. By default,
-no extension devices are enabled. We need a mechanism to allow
-users to enable and configure their extension devices. GTK provides
-the InputDialog widget to automate this process. The following
-procedure manages an InputDialog widget. It creates the dialog if
-it isn't present, and raises it to the top otherwise.
+  return dial->adjustment;
+}
 
-<tscreen><verb>
 void
-input_dialog_destroy (GtkWidget *w, gpointer data)
+gtk_dial_set_update_policy (GtkDial      *dial,
+                            GtkUpdateType  policy)
 {
-  *((GtkWidget **)data) = NULL;
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
+
+  dial->policy = policy;
 }
 
 void
-create_input_dialog ()
+gtk_dial_set_adjustment (GtkDial      *dial,
+                         GtkAdjustment *adjustment)
 {
-  static GtkWidget *inputd = NULL;
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-  if (!inputd)
+  if (dial->adjustment)
     {
-      inputd = gtk_input_dialog_new();
+      gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial);
+      gtk_object_unref (GTK_OBJECT (dial->adjustment));
+    }
 
-      gtk_signal_connect (GTK_OBJECT(inputd), "destroy",
-                         (GtkSignalFunc)input_dialog_destroy, &amp;inputd);
-      gtk_signal_connect_object (GTK_OBJECT(GTK_INPUT_DIALOG(inputd)->close_button),
-                                "clicked",
-                                (GtkSignalFunc)gtk_widget_hide,
-                                GTK_OBJECT(inputd));
-      gtk_widget_hide ( GTK_INPUT_DIALOG(inputd)->save_button);
+  dial->adjustment = adjustment;
+  gtk_object_ref (GTK_OBJECT (dial->adjustment));
 
-      gtk_widget_show (inputd);
-    }
-  else
-    {
-      if (!GTK_WIDGET_MAPPED(inputd))
-       gtk_widget_show(inputd);
-      else
-       gdk_window_raise(inputd->window);
-    }
+  gtk_signal_connect (GTK_OBJECT (adjustment), "changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_changed,
+                     (gpointer) dial);
+  gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed",
+                     (GtkSignalFunc) gtk_dial_adjustment_value_changed,
+                     (gpointer) dial);
+
+  dial->old_value = adjustment->value;
+  dial->old_lower = adjustment->lower;
+  dial->old_upper = adjustment->upper;
+
+  gtk_dial_update (dial);
 }
-</verb></tscreen>
 
-(You might want to take note of the way we handle this dialog.  By
-connecting to the "destroy" signal, we make sure that we don't keep a
-pointer to dialog around after it is destroyed - that could lead to a
-segfault.)
+static void
+gtk_dial_realize (GtkWidget *widget)
+{
+  GtkDial *dial;
+  GdkWindowAttr attributes;
+  gint attributes_mask;
 
-<p>
-The InputDialog has two buttons "Close" and "Save", which by default
-have no actions assigned to them. In the above function we make
-"Close" hide the dialog, hide the "Save" button, since we don't
-implement saving of XInput options in this program.
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
 
-<sect2> Using extended device information
+  GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
+  dial = GTK_DIAL (widget);
 
-<p>
-Once we've enabled the device, we can just use the extended 
-device information in the extra fields of the event structures.
-In fact, it is always safe to use this information since these
-fields will have reasonable default values even when extended
-events are not enabled.
+  attributes.x = widget->allocation.x;
+  attributes.y = widget->allocation.y;
+  attributes.width = widget->allocation.width;
+  attributes.height = widget->allocation.height;
+  attributes.wclass = GDK_INPUT_OUTPUT;
+  attributes.window_type = GDK_WINDOW_CHILD;
+  attributes.event_mask = gtk_widget_get_events (widget) | 
+    GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | 
+    GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
+    GDK_POINTER_MOTION_HINT_MASK;
+  attributes.visual = gtk_widget_get_visual (widget);
+  attributes.colormap = gtk_widget_get_colormap (widget);
 
-<p>
-Once change we do have to make is to call
-<tt/gdk_input_window_get_pointer()/ instead of
-<tt/gdk_window_get_pointer/. This is necessary because
-<tt/gdk_window_get_pointer/ doesn't return the extended device
-information.
+  attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+  widget->window = gdk_window_new (widget->parent->window, &amp;attributes, attributes_mask);
 
-<tscreen><verb>
-void gdk_input_window_get_pointer     (GdkWindow       *window,
-                                      guint32         deviceid,
-                                      gdouble         *x,
-                                      gdouble         *y,
-                                      gdouble         *pressure,
-                                      gdouble         *xtilt,
-                                      gdouble         *ytilt,
-                                      GdkModifierType *mask);
-</verb></tscreen>
+  widget->style = gtk_style_attach (widget->style, widget->window);
 
-When calling this function, we need to specify the device ID as
-well as the window. Usually, we'll get the device ID from the
-<tt/deviceid/ field of an event structure. Again, this function
-will return reasonable values when extension events are not
-enabled. (In this case, <tt/event->deviceid/ will have the value
-<tt/GDK_CORE_POINTER/).
+  gdk_window_set_user_data (widget->window, widget);
 
-So the basic structure of our button-press and motion event handlers,
-doesn't change much - we just need to add code to deal with the
-extended information.
+  gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE);
+}
+
+static void 
+gtk_dial_size_request (GtkWidget      *widget,
+                      GtkRequisition *requisition)
+{
+  requisition->width = DIAL_DEFAULT_SIZE;
+  requisition->height = DIAL_DEFAULT_SIZE;
+}
+
+static void
+gtk_dial_size_allocate (GtkWidget     *widget,
+                       GtkAllocation *allocation)
+{
+  GtkDial *dial;
+
+  g_return_if_fail (widget != NULL);
+  g_return_if_fail (GTK_IS_DIAL (widget));
+  g_return_if_fail (allocation != NULL);
+
+  widget->allocation = *allocation;
+  dial = GTK_DIAL (widget);
+
+  if (GTK_WIDGET_REALIZED (widget))
+    {
+
+      gdk_window_move_resize (widget->window,
+                             allocation->x, allocation->y,
+                             allocation->width, allocation->height);
+
+    }
+  dial->radius = MIN(allocation->width,allocation->height) * 0.45;
+  dial->pointer_width = dial->radius / 5;
+}
 
-<tscreen><verb>
 static gint
-button_press_event (GtkWidget *widget, GdkEventButton *event)
+gtk_dial_expose (GtkWidget      *widget,
+                GdkEventExpose *event)
 {
-  print_button_press (event->deviceid);
+  GtkDial *dial;
+  GdkPoint points[3];
+  gdouble s,c;
+  gdouble theta;
+  gint xc, yc;
+  gint tick_length;
+  gint i;
+
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  if (event->count > 0)
+    return FALSE;
   
-  if (event->button == 1 &amp;&amp; pixmap != NULL)
-    draw_brush (widget, event->source, event->x, event->y, event->pressure);
+  dial = GTK_DIAL (widget);
 
-  return TRUE;
-}
+  gdk_window_clear_area (widget->window,
+                        0, 0,
+                        widget->allocation.width,
+                        widget->allocation.height);
 
-static gint
-motion_notify_event (GtkWidget *widget, GdkEventMotion *event)
-{
-  gdouble x, y;
-  gdouble pressure;
-  GdkModifierType state;
+  xc = widget->allocation.width/2;
+  yc = widget->allocation.height/2;
 
-  if (event->is_hint)
-    gdk_input_window_get_pointer (event->window, event->deviceid,
-                                 &amp;x, &amp;y, &amp;pressure, NULL, NULL, &amp;state);
-  else
+  /* Draw ticks */
+
+  for (i=0; i<25; i++)
     {
-      x = event->x;
-      y = event->y;
-      pressure = event->pressure;
-      state = event->state;
+      theta = (i*M_PI/18. - M_PI/6.);
+      s = sin(theta);
+      c = cos(theta);
+
+      tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2;
+      
+      gdk_draw_line (widget->window,
+                    widget->style->fg_gc[widget->state],
+                    xc + c*(dial->radius - tick_length),
+                    yc - s*(dial->radius - tick_length),
+                    xc + c*dial->radius,
+                    yc - s*dial->radius);
     }
-    
-  if (state &amp; GDK_BUTTON1_MASK &amp;&amp; pixmap != NULL)
-    draw_brush (widget, event->source, x, y, pressure);
+
+  /* Draw pointer */
+
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+
+
+  points[0].x = xc + s*dial->pointer_width/2;
+  points[0].y = yc + c*dial->pointer_width/2;
+  points[1].x = xc + c*dial->radius;
+  points[1].y = yc - s*dial->radius;
+  points[2].x = xc - s*dial->pointer_width/2;
+  points[2].y = yc - c*dial->pointer_width/2;
+
+  gtk_draw_polygon (widget->style,
+                   widget->window,
+                   GTK_STATE_NORMAL,
+                   GTK_SHADOW_OUT,
+                   points, 3,
+                   TRUE);
   
-  return TRUE;
+  return FALSE;
 }
-</verb></tscreen>
-
-We also need to do something with the new information. Our new
-<tt/draw_brush()/ function draws with a different color for
-each <tt/event->source/ and changes the brush size depending
-on the pressure.
 
-<tscreen><verb>
-/* Draw a rectangle on the screen, size depending on pressure,
-   and color on the type of device */
-static void
-draw_brush (GtkWidget *widget, GdkInputSource source,
-           gdouble x, gdouble y, gdouble pressure)
+static gint
+gtk_dial_button_press (GtkWidget      *widget,
+                      GdkEventButton *event)
 {
-  GdkGC *gc;
-  GdkRectangle update_rect;
+  GtkDial *dial;
+  gint dx, dy;
+  double s, c;
+  double d_parallel;
+  double d_perpendicular;
 
-  switch (source)
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
+
+  dial = GTK_DIAL (widget);
+
+  /* Determine if button press was within pointer region - we 
+     do this by computing the parallel and perpendicular distance of
+     the point where the mouse was pressed from the line passing through
+     the pointer */
+  
+  dx = event->x - widget->allocation.width / 2;
+  dy = widget->allocation.height / 2 - event->y;
+  
+  s = sin(dial->angle);
+  c = cos(dial->angle);
+  
+  d_parallel = s*dy + c*dx;
+  d_perpendicular = fabs(s*dx - c*dy);
+  
+  if (!dial->button &amp;&amp;
+      (d_perpendicular < dial->pointer_width/2) &amp;&amp;
+      (d_parallel > - dial->pointer_width))
     {
-    case GDK_SOURCE_MOUSE:
-      gc = widget->style->dark_gc[GTK_WIDGET_STATE (widget)];
-      break;
-    case GDK_SOURCE_PEN:
-      gc = widget->style->black_gc;
-      break;
-    case GDK_SOURCE_ERASER:
-      gc = widget->style->white_gc;
-      break;
-    default:
-      gc = widget->style->light_gc[GTK_WIDGET_STATE (widget)];
+      gtk_grab_add (widget);
+
+      dial->button = event->button;
+
+      gtk_dial_update_mouse (dial, event->x, event->y);
     }
 
-  update_rect.x = x - 10 * pressure;
-  update_rect.y = y - 10 * pressure;
-  update_rect.width = 20 * pressure;
-  update_rect.height = 20 * pressure;
-  gdk_draw_rectangle (pixmap, gc, TRUE,
-                     update_rect.x, update_rect.y,
-                     update_rect.width, update_rect.height);
-  gtk_widget_draw (widget, &amp;update_rect);
+  return FALSE;
 }
-</verb></tscreen>
 
-<sect2> Finding out more about a device
+static gint
+gtk_dial_button_release (GtkWidget      *widget,
+                         GdkEventButton *event)
+{
+  GtkDial *dial;
 
-<p>
-As an example of how to find out more about a device, our program
-will print the name of the device that generates each button
-press. To find out the name of a device, we call the function:
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-<tscreen><verb>
-GList *gdk_input_list_devices               (void);
-</verb></tscreen>
+  dial = GTK_DIAL (widget);
 
-which returns a GList (a linked list type from the glib library)
-of GdkDeviceInfo structures. The GdkDeviceInfo strucure is defined
-as:
+  if (dial->button == event->button)
+    {
+      gtk_grab_remove (widget);
 
-<tscreen><verb>
-struct _GdkDeviceInfo
-{
-  guint32 deviceid;
-  gchar *name;
-  GdkInputSource source;
-  GdkInputMode mode;
-  gint has_cursor;
-  gint num_axes;
-  GdkAxisUse *axes;
-  gint num_keys;
-  GdkDeviceKey *keys;
-};
-</verb></tscreen>
+      dial->button = 0;
 
-Most of these fields are configuration information that you
-can ignore unless you are implemented XInput configuration
-saving. The we are interested in here is <tt/name/ which is
-simply the name that X assigns to the device. The other field
-that isn't configuration information is <tt/has_cursor/. If
-<tt/has_cursor/ is false, then we we need to draw our own
-cursor. But since we've specified <tt/GDK_EXTENSION_EVENTS_CURSOR/,
-we don't have to worry about this.
+      if (dial->policy == GTK_UPDATE_DELAYED)
+       gtk_timeout_remove (dial->timer);
+      
+      if ((dial->policy != GTK_UPDATE_CONTINUOUS) &amp;&amp;
+         (dial->old_value != dial->adjustment->value))
+       gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
 
-<p>
-Our <tt/print_button_press()/ function simply iterates through
-the returned list until it finds a match, then prints out
-the name of the device.
+  return FALSE;
+}
 
-<tscreen><verb>
-static void
-print_button_press (guint32 deviceid)
+static gint
+gtk_dial_motion_notify (GtkWidget      *widget,
+                        GdkEventMotion *event)
 {
-  GList *tmp_list;
+  GtkDial *dial;
+  GdkModifierType mods;
+  gint x, y, mask;
 
-  /* gdk_input_list_devices returns an internal list, so we shouldn't
-     free it afterwards */
-  tmp_list = gdk_input_list_devices();
+  g_return_val_if_fail (widget != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE);
+  g_return_val_if_fail (event != NULL, FALSE);
 
-  while (tmp_list)
+  dial = GTK_DIAL (widget);
+
+  if (dial->button != 0)
     {
-      GdkDeviceInfo *info = (GdkDeviceInfo *)tmp_list->data;
+      x = event->x;
+      y = event->y;
 
-      if (info->deviceid == deviceid)
+      if (event->is_hint || (event->window != widget->window))
+       gdk_window_get_pointer (widget->window, &amp;x, &amp;y, &amp;mods);
+
+      switch (dial->button)
        {
-         printf("Button press on device '%s'\n", info->name);
-         return;
+       case 1:
+         mask = GDK_BUTTON1_MASK;
+         break;
+       case 2:
+         mask = GDK_BUTTON2_MASK;
+         break;
+       case 3:
+         mask = GDK_BUTTON3_MASK;
+         break;
+       default:
+         mask = 0;
+         break;
        }
 
-      tmp_list = tmp_list->next;
+      if (mods &amp; mask)
+       gtk_dial_update_mouse (dial, x,y);
     }
+
+  return FALSE;
 }
-</verb></tscreen>
 
-That completes the changes to ``XInputize'' our program. As with
-the first version, the complete source is available at the location
-from which you got this tutorial, or from:
+static gint
+gtk_dial_timer (GtkDial *dial)
+{
+  g_return_val_if_fail (dial != NULL, FALSE);
+  g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE);
 
-<htmlurl url="http://www.gtk.org/~otaylor/gtk/tutorial/"
-name="http://www.gtk.org/~otaylor/gtk/tutorial/">
+  if (dial->policy == GTK_UPDATE_DELAYED)
+    gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
 
+  return FALSE;
+}
 
-<sect2> Further sophistications <label id="sec_Further_Sophistications">
+static void
+gtk_dial_update_mouse (GtkDial *dial, gint x, gint y)
+{
+  gint xc, yc;
+  gfloat old_value;
 
-<p>
-Although our program now supports XInput quite well, it lacks some
-features we would want in a full-featured application. First, the user
-probably doesn't want to have to configure their device each time they
-run the program, so we should allow them to save the device
-configuration. This is done by iterating through the return of
-<tt/gdk_input_list_devices()/ and writing out the configuration to a
-file.
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-<p>
-To restore the state next time the program is run, GDK provides
-functions to change device configuration:
+  xc = GTK_WIDGET(dial)->allocation.width / 2;
+  yc = GTK_WIDGET(dial)->allocation.height / 2;
 
-<tscreen><verb>
-gdk_input_set_extension_events()
-gdk_input_set_source()
-gdk_input_set_mode()
-gdk_input_set_axes()
-gdk_input_set_key()
-</verb></tscreen>
+  old_value = dial->adjustment->value;
+  dial->angle = atan2(yc-y, x-xc);
 
-(The list returned from <tt/gdk_input_list_devices()/ should not be
-modified directly.) An example of doing this can be found in the
-drawing program gsumi. (Available from <htmlurl
-url="http://www.msc.cornell.edu/~otaylor/gsumi/"
-name="http://www.msc.cornell.edu/~otaylor/gsumi/">) Eventually, it
-would be nice to have a standard way of doing this for all
-applications. This probably belongs at a slightly higher level than
-GTK, perhaps in the GNOME library.
+  if (dial->angle < -M_PI/2.)
+    dial->angle += 2*M_PI;
 
-<p>
-Another major ommission that we have mentioned above is the lack of
-cursor drawing. Platforms other than XFree86 currently do not allow
-simultaneously using a device as both the core pointer and directly by
-an application. See the <url
-url="http://www.msc.cornell.edu/~otaylor/xinput/XInput-HOWTO.html"
-name="XInput-HOWTO"> for more information about this. This means that
-applications that want to support the widest audience need to draw
-their own cursor.
+  if (dial->angle < -M_PI/6)
+    dial->angle = -M_PI/6;
 
-<p>
-An application that draws it's own cursor needs to do two things:
-determine if the current device needs a cursor drawn or not, and
-determine if the current device is in proximity. (If the current
-device is a drawing tablet, it's a nice touch to make the cursor 
-disappear when the stylus is lifted from the tablet. When the
-device is touching the stylus, that is called "in proximity.")
-The first is done by searching the device list, as we did
-to find out the device name. The second is achieved by selecting
-"proximity_out" events. An example of drawing one's own cursor is
-found in the 'testinput' program found in the GTK distribution.
+  if (dial->angle > 7.*M_PI/6.)
+    dial->angle = 7.*M_PI/6.;
 
-<!-- ***************************************************************** -->
-<sect>Tips For Writing GTK Applications
-<!-- ***************************************************************** -->
+  dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) *
+    (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.);
 
-<p>
-This section is simply a gathering of wisdom, general style guidelines and hints to
-creating good GTK applications. It is totally useless right now cause it's
-only a topic sentence :)
+  if (dial->adjustment->value != old_value)
+    {
+      if (dial->policy == GTK_UPDATE_CONTINUOUS)
+       {
+         gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+       }
+      else
+       {
+         gtk_widget_draw (GTK_WIDGET(dial), NULL);
 
-Use GNU autoconf and automake!  They are your friends :)  I am planning to
-make a quick intro on them here.
+         if (dial->policy == GTK_UPDATE_DELAYED)
+           {
+             if (dial->timer)
+               gtk_timeout_remove (dial->timer);
 
-<!-- ***************************************************************** -->
-<sect>Contributing
-<!-- ***************************************************************** -->
+             dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH,
+                                            (GtkFunction) gtk_dial_timer,
+                                            (gpointer) dial);
+           }
+       }
+    }
+}
 
-<p>
-This document, like so much other great software out there, was created for
-free by volunteers.  If you are at all knowledgeable about any aspect of GTK
-that does not already have documentation, please consider contributing to
-this document.
-<p>
-If you do decide to contribute, please mail your text to Tony Gale, 
-<tt><htmlurl url="mailto:gale@gtk.org"
-name="gale@gtk.org"></tt>. Also, be aware that the entirety of this 
-document is free, and any addition by yourself must also be free.  That is, 
-people may use any portion of your examples in their programs, and copies 
-of this document may be distributed at will etc.
-<p>
-Thank you.
+static void
+gtk_dial_update (GtkDial *dial)
+{
+  gfloat new_value;
+  
+  g_return_if_fail (dial != NULL);
+  g_return_if_fail (GTK_IS_DIAL (dial));
 
-<!-- ***************************************************************** -->
-<sect>Credits
-<!-- ***************************************************************** -->
-<p>
-I would like to thank the following for their contributions to this text.
+  new_value = dial->adjustment->value;
+  
+  if (new_value < dial->adjustment->lower)
+    new_value = dial->adjustment->lower;
 
-<itemize>
-<item>Bawer Dagdeviren, <tt><htmlurl url="mailto:chamele0n@geocities.com"
-name="chamele0n@geocities.com"></tt> for the menus tutorial.                         
+  if (new_value > dial->adjustment->upper)
+    new_value = dial->adjustment->upper;
 
-<item>Raph Levien, <tt><htmlurl url="mailto:raph@acm.org"
-name="raph@acm.org"></tt>
-for hello world ala GTK, widget packing, and general all around wisdom.
-He's also generously donated a home for this tutorial.
+  if (new_value != dial->adjustment->value)
+    {
+      dial->adjustment->value = new_value;
+      gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed");
+    }
 
-<item>Peter Mattis, <tt><htmlurl url="mailto:petm@xcf.berkeley.edu"
-name="petm@xcf.berkeley.edu"></tt> for the simplest GTK program.. 
-and the ability to make it :)
+  dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. /
+    (dial->adjustment->upper - dial->adjustment->lower);
 
-<item>Werner Koch <tt><htmlurl url="mailto:werner.koch@guug.de"
-name="werner.koch@guug.de"></tt> for converting the original plain text to
-SGML, and the widget class hierarchy.
+  gtk_widget_draw (GTK_WIDGET(dial), NULL);
+}
 
-<item>Mark Crichton <tt><htmlurl url="mailto:crichton@expert.cc.purdue.edu"
-name="crichton@expert.cc.purdue.edu"></tt> for the menu factory code, and
-the table packing tutorial.
+static void
+gtk_dial_adjustment_changed (GtkAdjustment *adjustment,
+                             gpointer       data)
+{
+  GtkDial *dial;
 
-<item>Owen Taylor <tt><htmlurl url="mailto:owt1@cornell.edu"
-name="owt1@cornell.edu"></tt> for the EventBox widget section (and
-the patch to the distro).  He's also responsible for the selections code and
-tutorial, as well as the sections on writing your own GTK widgets, and the
-example application.  Thanks a lot Owen for all you help!
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-<item>Mark VanderBoom <tt><htmlurl url="mailto:mvboom42@calvin.edu"
-name="mvboom42@calvin.edu"></tt> for his wonderful work on the Notebook,
-Progress Bar, Dialogs, and File selection widgets.  Thanks a lot Mark!
-You've been a great help.
+  dial = GTK_DIAL (data);
 
-<item>Tim Janik <tt><htmlurl url="mailto:timj@psynet.net"
-name="timj@psynet.net"></tt> for his great job on the Lists Widget.
-Thanks Tim :)
+  if ((dial->old_value != adjustment->value) ||
+      (dial->old_lower != adjustment->lower) ||
+      (dial->old_upper != adjustment->upper))
+    {
+      gtk_dial_update (dial);
 
-<item>Rajat Datta <tt><htmlurl url="mailto:rajat@ix.netcom.com"
-name="rajat@ix.netcom.com"</tt> for the excellent job on the Pixmap tutorial.
+      dial->old_value = adjustment->value;
+      dial->old_lower = adjustment->lower;
+      dial->old_upper = adjustment->upper;
+    }
+}
 
-<item>Michael K. Johnson <tt><htmlurl url="mailto:johnsonm@redhat.com"
-name="johnsonm@redhat.com"></tt> for info and code for popup menus. 
+static void
+gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment,
+                                   gpointer       data)
+{
+  GtkDial *dial;
 
-</itemize>
-<p>
-And to all of you who commented and helped refine this document.
-<p>
-Thanks.
+  g_return_if_fail (adjustment != NULL);
+  g_return_if_fail (data != NULL);
 
-<!-- ***************************************************************** -->
-<sect> Tutorial Copyright and Permissions Notice
-<!-- ***************************************************************** -->
+  dial = GTK_DIAL (data);
 
-<p>
-The GTK Tutorial is Copyright (C) 1997 Ian Main. 
+  if (dial->old_value != adjustment->value)
+    {
+      gtk_dial_update (dial);
 
-Copyright (C) 1998 Tony Gale.
-<p>
-Permission is granted to make and distribute verbatim copies of this 
-manual provided the copyright notice and this permission notice are 
-preserved on all copies.
-<P>Permission is granted to copy and distribute modified versions of 
-this document under the conditions for verbatim copying, provided that 
-this copyright notice is included exactly as in the original,
-and that the entire resulting derived work is distributed under 
-the terms of a permission notice identical to this one.
-<P>Permission is granted to copy and distribute translations of this 
-document into another language, under the above conditions for modified 
-versions.
-<P>If you are intending to incorporate this document into a published 
-work, please contact the maintainer, and we will make an effort 
-to ensure that you have the most up to date information available.
-<P>There is no guarentee that this document lives up to its intended
-purpose.  This is simply provided as a free resource.  As such,
-the authors and maintainers of the information provided within can
-not make any guarentee that the information is even accurate.
+      dial->old_value = adjustment->value;
+    }
+}
+/* example-end */
+</verb></tscreen>
 </article>
diff --git a/examples/text/Makefile b/examples/text/Makefile
new file mode 100644 (file)
index 0000000..b1e501a
--- /dev/null
@@ -0,0 +1,8 @@
+
+CC = gcc
+
+text: text.c 
+       $(CC) `gtk-config --cflags` `gtk-config --libs` text.c -o text
+
+clean: 
+       rm -f *.o text
diff --git a/examples/text/text.c b/examples/text/text.c
new file mode 100644 (file)
index 0000000..b6a0210
--- /dev/null
@@ -0,0 +1,181 @@
+/* example-start text text.c */
+
+/* text.c */
+
+#include <stdio.h>
+#include <gtk/gtk.h>
+
+void text_toggle_editable (GtkWidget *checkbutton,
+                          GtkWidget *text)
+{
+  gtk_text_set_editable(GTK_TEXT(text),
+                       GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void text_toggle_word_wrap (GtkWidget *checkbutton,
+                           GtkWidget *text)
+{
+  gtk_text_set_word_wrap(GTK_TEXT(text),
+                        GTK_TOGGLE_BUTTON(checkbutton)->active);
+}
+
+void close_application( GtkWidget *widget, gpointer data )
+{
+       gtk_main_quit();
+}
+
+int main (int argc, char *argv[])
+{
+  GtkWidget *window;
+  GtkWidget *box1;
+  GtkWidget *box2;
+  GtkWidget *hbox;
+  GtkWidget *button;
+  GtkWidget *check;
+  GtkWidget *separator;
+  GtkWidget *table;
+  GtkWidget *vscrollbar;
+  GtkWidget *text;
+  GdkColormap *cmap;
+  GdkColor colour;
+  GdkFont *fixed_font;
+
+  FILE *infile;
+
+  gtk_init (&argc, &argv);
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_widget_set_usize (window, 600, 500);
+  gtk_window_set_policy (GTK_WINDOW(window), TRUE, TRUE, FALSE);  
+  gtk_signal_connect (GTK_OBJECT (window), "destroy",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_window_set_title (GTK_WINDOW (window), "Text Widget Example");
+  gtk_container_border_width (GTK_CONTAINER (window), 0);
+  
+  
+  box1 = gtk_vbox_new (FALSE, 0);
+  gtk_container_add (GTK_CONTAINER (window), box1);
+  gtk_widget_show (box1);
+  
+  
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, TRUE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  
+  table = gtk_table_new (2, 2, FALSE);
+  gtk_table_set_row_spacing (GTK_TABLE (table), 0, 2);
+  gtk_table_set_col_spacing (GTK_TABLE (table), 0, 2);
+  gtk_box_pack_start (GTK_BOX (box2), table, TRUE, TRUE, 0);
+  gtk_widget_show (table);
+  
+  /* Create the GtkText widget */
+  text = gtk_text_new (NULL, NULL);
+  gtk_text_set_editable (GTK_TEXT (text), TRUE);
+  gtk_table_attach (GTK_TABLE (table), text, 0, 1, 0, 1,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL,
+                   GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (text);
+
+  /* Add a vertical scrollbar to the GtkText widget */
+  vscrollbar = gtk_vscrollbar_new (GTK_TEXT (text)->vadj);
+  gtk_table_attach (GTK_TABLE (table), vscrollbar, 1, 2, 0, 1,
+                   GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
+  gtk_widget_show (vscrollbar);
+
+  /* Get the system colour map and allocate the colour red */
+  cmap = gdk_colormap_get_system();
+  colour.red = 0xffff;
+  colour.green = 0;
+  colour.blue = 0;
+  if (!gdk_color_alloc(cmap, &colour)) {
+    g_error("couldn't allocate colour");
+  }
+
+  /* Load a fixed font */
+  fixed_font = gdk_font_load ("-misc-fixed-medium-r-*-*-*-140-*-*-*-*-*-*");
+
+  /* Realizing a widget creates a window for it, ready for us to insert some text */
+  gtk_widget_realize (text);
+
+  /* Freeze the text widget, ready for multiple updates */
+  gtk_text_freeze (GTK_TEXT (text));
+  
+  /* Insert some coloured text */
+  gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
+                  "Supports ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &colour, NULL,
+                  "colored ", -1);
+  gtk_text_insert (GTK_TEXT (text), NULL, &text->style->black, NULL,
+                  "text and different ", -1);
+  gtk_text_insert (GTK_TEXT (text), fixed_font, &text->style->black, NULL,
+                  "fonts\n\n", -1);
+  
+  /* Load the file text.c into the text window */
+
+  infile = fopen("text.c", "r");
+  
+  if (infile) {
+    char buffer[1024];
+    int nchars;
+    
+    while (1)
+      {
+       nchars = fread(buffer, 1, 1024, infile);
+       gtk_text_insert (GTK_TEXT (text), fixed_font, NULL,
+                        NULL, buffer, nchars);
+       
+       if (nchars < 1024)
+         break;
+      }
+    
+    fclose (infile);
+  }
+
+  /* Thaw the text widget, allowing the updates to become visible */  
+  gtk_text_thaw (GTK_TEXT (text));
+  
+  hbox = gtk_hbutton_box_new ();
+  gtk_box_pack_start (GTK_BOX (box2), hbox, FALSE, FALSE, 0);
+  gtk_widget_show (hbox);
+
+  check = gtk_check_button_new_with_label("Editable");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, FALSE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_editable), text);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), TRUE);
+  gtk_widget_show (check);
+  check = gtk_check_button_new_with_label("Wrap Words");
+  gtk_box_pack_start (GTK_BOX (hbox), check, FALSE, TRUE, 0);
+  gtk_signal_connect (GTK_OBJECT(check), "toggled",
+                     GTK_SIGNAL_FUNC(text_toggle_word_wrap), text);
+  gtk_toggle_button_set_state(GTK_TOGGLE_BUTTON(check), FALSE);
+  gtk_widget_show (check);
+
+  separator = gtk_hseparator_new ();
+  gtk_box_pack_start (GTK_BOX (box1), separator, FALSE, TRUE, 0);
+  gtk_widget_show (separator);
+
+  box2 = gtk_vbox_new (FALSE, 10);
+  gtk_container_border_width (GTK_CONTAINER (box2), 10);
+  gtk_box_pack_start (GTK_BOX (box1), box2, FALSE, TRUE, 0);
+  gtk_widget_show (box2);
+  
+  button = gtk_button_new_with_label ("close");
+  gtk_signal_connect (GTK_OBJECT (button), "clicked",
+                     GTK_SIGNAL_FUNC(close_application),
+                     NULL);
+  gtk_box_pack_start (GTK_BOX (box2), button, TRUE, TRUE, 0);
+  GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
+  gtk_widget_grab_default (button);
+  gtk_widget_show (button);
+
+  gtk_widget_show (window);
+
+  gtk_main ();
+  
+  return 0;       
+}
+/* example-end */
diff --git a/examples/tree/Makefile b/examples/tree/Makefile
new file mode 100644 (file)
index 0000000..4f9c70a
--- /dev/null
@@ -0,0 +1,8 @@
+
+CC = gcc
+
+tree: tree.c 
+       $(CC) `gtk-config --cflags` `gtk-config --libs` tree.c -o tree
+
+clean: 
+       rm -f *.o tree
diff --git a/examples/tree/tree.c b/examples/tree/tree.c
new file mode 100644 (file)
index 0000000..3b19f8d
--- /dev/null
@@ -0,0 +1,178 @@
+/* example-start tree tree.c */
+
+#include <gtk/gtk.h>
+
+/* for all the GtkItem:: and GtkTreeItem:: signals */
+static void cb_itemsignal (GtkWidget *item, gchar *signame)
+{
+  gchar *name;
+  GtkLabel *label;
+
+  /* It's a GtkBin, so it has one child, which we know to be a
+     label, so get that */
+  label = GTK_LABEL (GTK_BIN (item)->child);
+  /* Get the text of the label */
+  gtk_label_get (label, &name);
+  /* Get the level of the tree which the item is in */
+  g_print ("%s called for item %s->%p, level %d\n", signame, name,
+          item, GTK_TREE (item->parent)->level);
+}
+
+/* Note that this is never called */
+static void cb_unselect_child (GtkWidget *root_tree, GtkWidget *child,
+                              GtkWidget *subtree)
+{
+  g_print ("unselect_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
+}
+
+/* Note that this is called every time the user clicks on an item,
+   whether it is already selected or not. */
+static void cb_select_child (GtkWidget *root_tree, GtkWidget *child,
+                            GtkWidget *subtree)
+{
+  g_print ("select_child called for root tree %p, subtree %p, child %p\n",
+          root_tree, subtree, child);
+}
+
+static void cb_selection_changed (GtkWidget *tree)
+{
+  GList *i;
+  
+  g_print ("selection_change called for tree %p\n", tree);
+  g_print ("selected objects are:\n");
+
+  i = GTK_TREE_SELECTION(tree);
+  while (i){
+    gchar *name;
+    GtkLabel *label;
+    GtkWidget *item;
+
+    /* Get a GtkWidget pointer from the list node */
+    item = GTK_WIDGET (i->data);
+    label = GTK_LABEL (GTK_BIN (item)->child);
+    gtk_label_get (label, &name);
+    g_print ("\t%s on level %d\n", name, GTK_TREE
+            (item->parent)->level);
+    i = i->next;
+  }
+}
+
+int main (int argc, char *argv[])
+{
+  GtkWidget *window, *scrolled_win, *tree;
+  static gchar *itemnames[] = {"Foo", "Bar", "Baz", "Quux",
+                              "Maurice"};
+  gint i;
+
+  gtk_init (&argc, &argv);
+
+  /* a generic toplevel window */
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_signal_connect (GTK_OBJECT(window), "delete_event",
+                     GTK_SIGNAL_FUNC (gtk_main_quit), NULL);
+  gtk_container_border_width (GTK_CONTAINER(window), 5);
+
+  /* A generic scrolled window */
+  scrolled_win = gtk_scrolled_window_new (NULL, NULL);
+  gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_win),
+                                 GTK_POLICY_AUTOMATIC,
+                                 GTK_POLICY_AUTOMATIC);
+  gtk_widget_set_usize (scrolled_win, 150, 200);
+  gtk_container_add (GTK_CONTAINER(window), scrolled_win);
+  gtk_widget_show (scrolled_win);
+  
+  /* Create the root tree */
+  tree = gtk_tree_new();
+  g_print ("root tree is %p\n", tree);
+  /* connect all GtkTree:: signals */
+  gtk_signal_connect (GTK_OBJECT(tree), "select_child",
+                     GTK_SIGNAL_FUNC(cb_select_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "unselect_child",
+                     GTK_SIGNAL_FUNC(cb_unselect_child), tree);
+  gtk_signal_connect (GTK_OBJECT(tree), "selection_changed",
+                     GTK_SIGNAL_FUNC(cb_selection_changed), tree);
+  /* Add it to the scrolled window */
+  gtk_container_add (GTK_CONTAINER(scrolled_win), tree);
+  /* Set the selection mode */
+  gtk_tree_set_selection_mode (GTK_TREE(tree),
+                              GTK_SELECTION_MULTIPLE);
+  /* Show it */
+  gtk_widget_show (tree);
+
+  for (i = 0; i < 5; i++){
+    GtkWidget *subtree, *item;
+    gint j;
+
+    /* Create a tree item */
+    item = gtk_tree_item_new_with_label (itemnames[i]);
+    /* Connect all GtkItem:: and GtkTreeItem:: signals */
+    gtk_signal_connect (GTK_OBJECT(item), "select",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+    gtk_signal_connect (GTK_OBJECT(item), "deselect",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+    gtk_signal_connect (GTK_OBJECT(item), "toggle",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+    gtk_signal_connect (GTK_OBJECT(item), "expand",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+    gtk_signal_connect (GTK_OBJECT(item), "collapse",
+                       GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+    /* Add it to the parent tree */
+    gtk_tree_append (GTK_TREE(tree), item);
+    /* Show it - this can be done at any time */
+    gtk_widget_show (item);
+    /* Create this item's subtree */
+    subtree = gtk_tree_new();
+    g_print ("-> item %s->%p, subtree %p\n", itemnames[i], item,
+            subtree);
+
+    /* This is still necesary if you want these signals to be called
+       for the subtree's children.  Note that selection_change will be 
+       signalled for the root tree regardless. */
+    gtk_signal_connect (GTK_OBJECT(subtree), "select_child",
+                       GTK_SIGNAL_FUNC(cb_select_child), subtree);
+    gtk_signal_connect (GTK_OBJECT(subtree), "unselect_child",
+                       GTK_SIGNAL_FUNC(cb_unselect_child), subtree);
+    /* This has absolutely no effect, because it is completely ignored 
+       in subtrees */
+    gtk_tree_set_selection_mode (GTK_TREE(subtree),
+                                GTK_SELECTION_SINGLE);
+    /* Neither does this, but for a rather different reason - the
+       view_mode and view_line values of a tree are propagated to
+       subtrees when they are mapped.  So, setting it later on would
+       actually have a (somewhat unpredictable) effect */
+    gtk_tree_set_view_mode (GTK_TREE(subtree), GTK_TREE_VIEW_ITEM);
+    /* Set this item's subtree - note that you cannot do this until
+       AFTER the item has been added to its parent tree! */
+    gtk_tree_item_set_subtree (GTK_TREE_ITEM(item), subtree);
+
+    for (j = 0; j < 5; j++){
+      GtkWidget *subitem;
+
+      /* Create a subtree item, in much the same way */
+      subitem = gtk_tree_item_new_with_label (itemnames[j]);
+      /* Connect all GtkItem:: and GtkTreeItem:: signals */
+      gtk_signal_connect (GTK_OBJECT(subitem), "select",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "select");
+      gtk_signal_connect (GTK_OBJECT(subitem), "deselect",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "deselect");
+      gtk_signal_connect (GTK_OBJECT(subitem), "toggle",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "toggle");
+      gtk_signal_connect (GTK_OBJECT(subitem), "expand",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "expand");
+      gtk_signal_connect (GTK_OBJECT(subitem), "collapse",
+                         GTK_SIGNAL_FUNC(cb_itemsignal), "collapse");
+      g_print ("-> -> item %s->%p\n", itemnames[j], subitem);
+      /* Add it to its parent tree */
+      gtk_tree_append (GTK_TREE(subtree), subitem);
+      /* Show it */
+      gtk_widget_show (subitem);
+    }
+  }
+
+  /* Show the window and loop endlessly */
+  gtk_widget_show (window);
+  gtk_main();
+  return 0;
+}
+/* example-end */